LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - ks_keychain.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 2 2 100.0 %
Date: 2024-04-21 15:09:00 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2007 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "hx_locl.h"
      35             : 
      36             : #ifdef HAVE_FRAMEWORK_SECURITY
      37             : 
      38             : #pragma clang diagnostic push
      39             : #pragma clang diagnostic ignored "-Wdeprecated-declarations"
      40             : 
      41             : #include <Security/Security.h>
      42             : 
      43             : /* Missing function decls in pre Leopard */
      44             : #ifdef NEED_SECKEYGETCSPHANDLE_PROTO
      45             : OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
      46             : OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
      47             :                               int, const CSSM_ACCESS_CREDENTIALS **);
      48             : #define kSecCredentialTypeDefault 0
      49             : #define CSSM_SIZE uint32_t
      50             : #endif
      51             : 
      52             : 
      53             : static int
      54             : getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
      55             :              SecKeychainAttributeList **attrs)
      56             : {
      57             :     SecKeychainAttributeInfo attrInfo;
      58             :     UInt32 attrFormat = 0;
      59             :     OSStatus ret;
      60             : 
      61             :     *attrs = NULL;
      62             : 
      63             :     attrInfo.count = 1;
      64             :     attrInfo.tag = &item;
      65             :     attrInfo.format = &attrFormat;
      66             : 
      67             :     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
      68             :                                                attrs, NULL, NULL);
      69             :     if (ret)
      70             :         return EINVAL;
      71             :     return 0;
      72             : }
      73             : 
      74             : 
      75             : /*
      76             :  *
      77             :  */
      78             : 
      79             : struct kc_rsa {
      80             :     SecKeychainItemRef item;
      81             :     size_t keysize;
      82             : };
      83             : 
      84             : 
      85             : static int
      86             : kc_rsa_public_encrypt(int flen,
      87             :                       const unsigned char *from,
      88             :                       unsigned char *to,
      89             :                       RSA *rsa,
      90             :                       int padding)
      91             : {
      92             :     return -1;
      93             : }
      94             : 
      95             : static int
      96             : kc_rsa_public_decrypt(int flen,
      97             :                       const unsigned char *from,
      98             :                       unsigned char *to,
      99             :                       RSA *rsa,
     100             :                       int padding)
     101             : {
     102             :     return -1;
     103             : }
     104             : 
     105             : 
     106             : static int
     107             : kc_rsa_private_encrypt(int flen,
     108             :                        const unsigned char *from,
     109             :                        unsigned char *to,
     110             :                        RSA *rsa,
     111             :                        int padding)
     112             : {
     113             :     struct kc_rsa *kc = RSA_get_app_data(rsa);
     114             : 
     115             :     CSSM_RETURN cret;
     116             :     OSStatus ret;
     117             :     const CSSM_ACCESS_CREDENTIALS *creds;
     118             :     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
     119             :     CSSM_CSP_HANDLE cspHandle;
     120             :     const CSSM_KEY *cssmKey;
     121             :     CSSM_CC_HANDLE sigHandle = 0;
     122             :     CSSM_DATA sig, in;
     123             :     int fret = 0;
     124             : 
     125             :     if (padding != RSA_PKCS1_PADDING)
     126             :         return -1;
     127             : 
     128             :     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
     129             :     if(cret) abort();
     130             : 
     131             :     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
     132             :     if(cret) abort();
     133             : 
     134             :     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
     135             :                                kSecCredentialTypeDefault, &creds);
     136             :     if(ret) abort();
     137             : 
     138             :     ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
     139             :                                           creds, cssmKey, &sigHandle);
     140             :     if(ret) abort();
     141             : 
     142             :     in.Data = (uint8 *)from;
     143             :     in.Length = flen;
     144             : 
     145             :     sig.Data = (uint8 *)to;
     146             :     sig.Length = kc->keysize;
     147             : 
     148             :     cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
     149             :     if(cret) {
     150             :         /* cssmErrorString(cret); */
     151             :         fret = -1;
     152             :     } else
     153             :         fret = sig.Length;
     154             : 
     155             :     if(sigHandle)
     156             :         CSSM_DeleteContext(sigHandle);
     157             : 
     158             :     return fret;
     159             : }
     160             : 
     161             : static int
     162             : kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
     163             :                        RSA * rsa, int padding)
     164             : {
     165             :     struct kc_rsa *kc = RSA_get_app_data(rsa);
     166             : 
     167             :     CSSM_RETURN cret;
     168             :     OSStatus ret;
     169             :     const CSSM_ACCESS_CREDENTIALS *creds;
     170             :     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
     171             :     CSSM_CSP_HANDLE cspHandle;
     172             :     const CSSM_KEY *cssmKey;
     173             :     CSSM_CC_HANDLE handle = 0;
     174             :     CSSM_DATA out, in, rem;
     175             :     int fret = 0;
     176             :     CSSM_SIZE outlen = 0;
     177             :     char remdata[1024];
     178             : 
     179             :     if (padding != RSA_PKCS1_PADDING)
     180             :         return -1;
     181             : 
     182             :     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
     183             :     if(cret) abort();
     184             : 
     185             :     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
     186             :     if(cret) abort();
     187             : 
     188             :     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
     189             :                                kSecCredentialTypeDefault, &creds);
     190             :     if(ret) abort();
     191             : 
     192             : 
     193             :     ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
     194             :                                             CSSM_ALGID_RSA,
     195             :                                             creds,
     196             :                                             cssmKey,
     197             :                                             CSSM_PADDING_PKCS1,
     198             :                                             &handle);
     199             :     if(ret) abort();
     200             : 
     201             :     in.Data = (uint8 *)from;
     202             :     in.Length = flen;
     203             : 
     204             :     out.Data = (uint8 *)to;
     205             :     out.Length = kc->keysize;
     206             : 
     207             :     rem.Data = (uint8 *)remdata;
     208             :     rem.Length = sizeof(remdata);
     209             : 
     210             :     cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
     211             :     if(cret) {
     212             :         /* cssmErrorString(cret); */
     213             :         fret = -1;
     214             :     } else
     215             :         fret = out.Length;
     216             : 
     217             :     if(handle)
     218             :         CSSM_DeleteContext(handle);
     219             : 
     220             :     return fret;
     221             : }
     222             : 
     223             : static int
     224             : kc_rsa_init(RSA *rsa)
     225             : {
     226             :     return 1;
     227             : }
     228             : 
     229             : static int
     230             : kc_rsa_finish(RSA *rsa)
     231             : {
     232             :     struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
     233             :     CFRelease(kc_rsa->item);
     234             :     memset(kc_rsa, 0, sizeof(*kc_rsa));
     235             :     free(kc_rsa);
     236             :     return 1;
     237             : }
     238             : 
     239             : static const RSA_METHOD kc_rsa_pkcs1_method = {
     240             :     "hx509 Keychain PKCS#1 RSA",
     241             :     kc_rsa_public_encrypt,
     242             :     kc_rsa_public_decrypt,
     243             :     kc_rsa_private_encrypt,
     244             :     kc_rsa_private_decrypt,
     245             :     NULL,
     246             :     NULL,
     247             :     kc_rsa_init,
     248             :     kc_rsa_finish,
     249             :     0,
     250             :     NULL,
     251             :     NULL,
     252             :     NULL,
     253             :     NULL
     254             : };
     255             : 
     256             : static int
     257             : set_private_key(hx509_context context,
     258             :                 SecKeychainItemRef itemRef,
     259             :                 hx509_cert cert)
     260             : {
     261             :     struct kc_rsa *kc;
     262             :     hx509_private_key key;
     263             :     RSA *rsa;
     264             :     int ret;
     265             : 
     266             :     ret = hx509_private_key_init(&key, NULL, NULL);
     267             :     if (ret)
     268             :         return ret;
     269             : 
     270             :     kc = calloc(1, sizeof(*kc));
     271             :     if (kc == NULL)
     272             :         _hx509_abort("out of memory");
     273             : 
     274             :     kc->item = itemRef;
     275             : 
     276             :     rsa = RSA_new();
     277             :     if (rsa == NULL)
     278             :         _hx509_abort("out of memory");
     279             : 
     280             :     /* Argh, fake modulus since OpenSSL API is on crack */
     281             :     {
     282             :         SecKeychainAttributeList *attrs = NULL;
     283             :         uint32_t size;
     284             :         void *data;
     285             : 
     286             :         rsa->n = BN_new();
     287             :         if (rsa->n == NULL) abort();
     288             : 
     289             :         ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
     290             :         if (ret) abort();
     291             : 
     292             :         size = *(uint32_t *)attrs->attr[0].data;
     293             :         SecKeychainItemFreeAttributesAndData(attrs, NULL);
     294             : 
     295             :         kc->keysize = (size + 7) / 8;
     296             : 
     297             :         data = malloc(kc->keysize);
     298             :         memset(data, 0xe0, kc->keysize);
     299             :         BN_bin2bn(data, kc->keysize, rsa->n);
     300             :         free(data);
     301             :     }
     302             :     rsa->e = NULL;
     303             : 
     304             :     RSA_set_method(rsa, &kc_rsa_pkcs1_method);
     305             :     ret = RSA_set_app_data(rsa, kc);
     306             :     if (ret != 1)
     307             :         _hx509_abort("RSA_set_app_data");
     308             : 
     309             :     hx509_private_key_assign_rsa(key, rsa);
     310             :     _hx509_cert_assign_key(cert, key);
     311             : 
     312             :     return 0;
     313             : }
     314             : 
     315             : /*
     316             :  *
     317             :  */
     318             : 
     319             : struct ks_keychain {
     320             :     int anchors;
     321             :     SecKeychainRef keychain;
     322             : };
     323             : 
     324             : static int
     325             : keychain_init(hx509_context context,
     326             :               hx509_certs certs, void **data, int flags,
     327             :               const char *residue, hx509_lock lock)
     328             : {
     329             :     struct ks_keychain *ctx;
     330             : 
     331             :     if (flags & HX509_CERTS_NO_PRIVATE_KEYS) {
     332             :         hx509_set_error_string(context, 0, ENOTSUP,
     333             :                                "KEYCHAIN store does not support not reading "
     334             :                                "private keys");
     335             :         return ENOTSUP;
     336             :     }
     337             : 
     338             :     ctx = calloc(1, sizeof(*ctx));
     339             :     if (ctx == NULL) {
     340             :         hx509_clear_error_string(context);
     341             :         return ENOMEM;
     342             :     }
     343             : 
     344             :     if (residue) {
     345             :         if (strcasecmp(residue, "system-anchors") == 0) {
     346             :             ctx->anchors = 1;
     347             :         } else if (strncasecmp(residue, "FILE:", 5) == 0) {
     348             :             OSStatus ret;
     349             : 
     350             :             ret = SecKeychainOpen(residue + 5, &ctx->keychain);
     351             :             if (ret != noErr) {
     352             :                 hx509_set_error_string(context, 0, ENOENT,
     353             :                                        "Failed to open %s", residue);
     354             :                 free(ctx);
     355             :                 return ENOENT;
     356             :             }
     357             :         } else {
     358             :             hx509_set_error_string(context, 0, ENOENT,
     359             :                                    "Unknown subtype %s", residue);
     360             :             free(ctx);
     361             :             return ENOENT;
     362             :         }
     363             :     }
     364             : 
     365             :     *data = ctx;
     366             :     return 0;
     367             : }
     368             : 
     369             : /*
     370             :  *
     371             :  */
     372             : 
     373             : static int
     374             : keychain_free(hx509_certs certs, void *data)
     375             : {
     376             :     struct ks_keychain *ctx = data;
     377             :     if (ctx->keychain)
     378             :         CFRelease(ctx->keychain);
     379             :     memset(ctx, 0, sizeof(*ctx));
     380             :     free(ctx);
     381             :     return 0;
     382             : }
     383             : 
     384             : /*
     385             :  *
     386             :  */
     387             : 
     388             : struct iter {
     389             :     hx509_certs certs;
     390             :     void *cursor;
     391             :     SecKeychainSearchRef searchRef;
     392             : };
     393             : 
     394             : static int
     395             : keychain_iter_start(hx509_context context,
     396             :                     hx509_certs certs, void *data, void **cursor)
     397             : {
     398             :     struct ks_keychain *ctx = data;
     399             :     struct iter *iter;
     400             : 
     401             :     iter = calloc(1, sizeof(*iter));
     402             :     if (iter == NULL) {
     403             :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     404             :         return ENOMEM;
     405             :     }
     406             : 
     407             :     if (ctx->anchors) {
     408             :         CFArrayRef anchors;
     409             :         int ret;
     410             :         int i;
     411             : 
     412             :         ret = hx509_certs_init(context, "MEMORY:ks-file-create",
     413             :                                0, NULL, &iter->certs);
     414             :         if (ret) {
     415             :             free(iter);
     416             :             return ret;
     417             :         }
     418             : 
     419             :         ret = SecTrustCopyAnchorCertificates(&anchors);
     420             :         if (ret != 0) {
     421             :             hx509_certs_free(&iter->certs);
     422             :             free(iter);
     423             :             hx509_set_error_string(context, 0, ENOMEM,
     424             :                                    "Can't get trust anchors from Keychain");
     425             :             return ENOMEM;
     426             :         }
     427             :         for (i = 0; i < CFArrayGetCount(anchors); i++) {
     428             :             SecCertificateRef cr;
     429             :             hx509_cert cert;
     430             :             CSSM_DATA cssm;
     431             : 
     432             :             cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
     433             : 
     434             :             SecCertificateGetData(cr, &cssm);
     435             : 
     436             :             cert = hx509_cert_init_data(context, cssm.Data, cssm.Length, NULL);
     437             :             if (cert == NULL)
     438             :                 continue;
     439             : 
     440             :             ret = hx509_certs_add(context, iter->certs, cert);
     441             :             hx509_cert_free(cert);
     442             :         }
     443             :         CFRelease(anchors);
     444             :     }
     445             : 
     446             :     if (iter->certs) {
     447             :         int ret;
     448             :         ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
     449             :         if (ret) {
     450             :             hx509_certs_free(&iter->certs);
     451             :             free(iter);
     452             :             return ret;
     453             :         }
     454             :     } else {
     455             :         OSStatus ret;
     456             : 
     457             :         ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
     458             :                                                     kSecCertificateItemClass,
     459             :                                                     NULL,
     460             :                                                     &iter->searchRef);
     461             :         if (ret) {
     462             :             free(iter);
     463             :             hx509_set_error_string(context, 0, ret,
     464             :                                    "Failed to start search for attributes");
     465             :             return ENOMEM;
     466             :         }
     467             :     }
     468             : 
     469             :     *cursor = iter;
     470             :     return 0;
     471             : }
     472             : 
     473             : /*
     474             :  *
     475             :  */
     476             : 
     477             : static int
     478             : keychain_iter(hx509_context context,
     479             :               hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
     480             : {
     481             :     SecKeychainAttributeList *attrs = NULL;
     482             :     SecKeychainAttributeInfo attrInfo;
     483             :     UInt32 attrFormat[1] = { 0 };
     484             :     SecKeychainItemRef itemRef;
     485             :     SecItemAttr item[1];
     486             :     heim_error_t error = NULL;
     487             :     struct iter *iter = cursor;
     488             :     OSStatus ret;
     489             :     UInt32 len;
     490             :     void *ptr = NULL;
     491             : 
     492             :     if (iter->certs)
     493             :         return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
     494             : 
     495             :     *cert = NULL;
     496             : 
     497             :     ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
     498             :     if (ret == errSecItemNotFound)
     499             :         return 0;
     500             :     else if (ret != 0)
     501             :         return EINVAL;
     502             : 
     503             :     /*
     504             :      * Pick out certificate and matching "keyid"
     505             :      */
     506             : 
     507             :     item[0] = kSecPublicKeyHashItemAttr;
     508             : 
     509             :     attrInfo.count = 1;
     510             :     attrInfo.tag = item;
     511             :     attrInfo.format = attrFormat;
     512             : 
     513             :     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
     514             :                                                &attrs, &len, &ptr);
     515             :     if (ret)
     516             :         return EINVAL;
     517             : 
     518             :     *cert = hx509_cert_init_data(context, ptr, len, &error);
     519             :     if (*cert == NULL) {
     520             :         ret = heim_error_get_code(error);
     521             :         heim_release(error);
     522             :         goto out;
     523             :     }
     524             : 
     525             :     /*
     526             :      * Find related private key if there is one by looking at
     527             :      * kSecPublicKeyHashItemAttr == kSecKeyLabel
     528             :      */
     529             :     {
     530             :         SecKeychainSearchRef search;
     531             :         SecKeychainAttribute attrKeyid;
     532             :         SecKeychainAttributeList attrList;
     533             : 
     534             :         attrKeyid.tag = kSecKeyLabel;
     535             :         attrKeyid.length = attrs->attr[0].length;
     536             :         attrKeyid.data = attrs->attr[0].data;
     537             : 
     538             :         attrList.count = 1;
     539             :         attrList.attr = &attrKeyid;
     540             : 
     541             :         ret = SecKeychainSearchCreateFromAttributes(NULL,
     542             :                                                     CSSM_DL_DB_RECORD_PRIVATE_KEY,
     543             :                                                     &attrList,
     544             :                                                     &search);
     545             :         if (ret) {
     546             :             ret = 0;
     547             :             goto out;
     548             :         }
     549             : 
     550             :         ret = SecKeychainSearchCopyNext(search, &itemRef);
     551             :         CFRelease(search);
     552             :         if (ret == errSecItemNotFound) {
     553             :             ret = 0;
     554             :             goto out;
     555             :         } else if (ret) {
     556             :             ret = EINVAL;
     557             :             goto out;
     558             :         }
     559             :         set_private_key(context, itemRef, *cert);
     560             :     }
     561             : 
     562             : out:
     563             :     SecKeychainItemFreeAttributesAndData(attrs, ptr);
     564             : 
     565             :     return ret;
     566             : }
     567             : 
     568             : /*
     569             :  *
     570             :  */
     571             : 
     572             : static int
     573             : keychain_iter_end(hx509_context context,
     574             :                   hx509_certs certs,
     575             :                   void *data,
     576             :                   void *cursor)
     577             : {
     578             :     struct iter *iter = cursor;
     579             : 
     580             :     if (iter->certs) {
     581             :         hx509_certs_end_seq(context, iter->certs, iter->cursor);
     582             :         hx509_certs_free(&iter->certs);
     583             :     } else {
     584             :         CFRelease(iter->searchRef);
     585             :     }
     586             : 
     587             :     memset(iter, 0, sizeof(*iter));
     588             :     free(iter);
     589             :     return 0;
     590             : }
     591             : 
     592             : /*
     593             :  *
     594             :  */
     595             : 
     596             : struct hx509_keyset_ops keyset_keychain = {
     597             :     "KEYCHAIN",
     598             :     0,
     599             :     keychain_init,
     600             :     NULL,
     601             :     keychain_free,
     602             :     NULL,
     603             :     NULL,
     604             :     keychain_iter_start,
     605             :     keychain_iter,
     606             :     keychain_iter_end,
     607             :     NULL,
     608             :     NULL,
     609             :     NULL,
     610             :     NULL
     611             : };
     612             : 
     613             : #pragma clang diagnostic pop
     614             : 
     615             : #endif /* HAVE_FRAMEWORK_SECURITY */
     616             : 
     617             : /*
     618             :  *
     619             :  */
     620             : 
     621             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     622      792004 : _hx509_ks_keychain_register(hx509_context context)
     623             : {
     624             : #ifdef HAVE_FRAMEWORK_SECURITY
     625             :     _hx509_ks_register(context, &keyset_keychain);
     626             : #endif
     627      792004 : }

Generated by: LCOV version 1.14