Path: blob/main/crypto/heimdal/lib/hx509/ks_keychain.c
34878 views
/*1* Copyright (c) 2007 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "hx_locl.h"3435#ifdef HAVE_FRAMEWORK_SECURITY3637#include <Security/Security.h>3839/* Missing function decls in pre Leopard */40#ifdef NEED_SECKEYGETCSPHANDLE_PROTO41OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);42OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,43int, const CSSM_ACCESS_CREDENTIALS **);44#define kSecCredentialTypeDefault 045#define CSSM_SIZE uint32_t46#endif474849static int50getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,51SecKeychainAttributeList **attrs)52{53SecKeychainAttributeInfo attrInfo;54UInt32 attrFormat = 0;55OSStatus ret;5657*attrs = NULL;5859attrInfo.count = 1;60attrInfo.tag = &item;61attrInfo.format = &attrFormat;6263ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,64attrs, NULL, NULL);65if (ret)66return EINVAL;67return 0;68}697071/*72*73*/7475struct kc_rsa {76SecKeychainItemRef item;77size_t keysize;78};798081static int82kc_rsa_public_encrypt(int flen,83const unsigned char *from,84unsigned char *to,85RSA *rsa,86int padding)87{88return -1;89}9091static int92kc_rsa_public_decrypt(int flen,93const unsigned char *from,94unsigned char *to,95RSA *rsa,96int padding)97{98return -1;99}100101102static int103kc_rsa_private_encrypt(int flen,104const unsigned char *from,105unsigned char *to,106RSA *rsa,107int padding)108{109struct kc_rsa *kc = RSA_get_app_data(rsa);110111CSSM_RETURN cret;112OSStatus ret;113const CSSM_ACCESS_CREDENTIALS *creds;114SecKeyRef privKeyRef = (SecKeyRef)kc->item;115CSSM_CSP_HANDLE cspHandle;116const CSSM_KEY *cssmKey;117CSSM_CC_HANDLE sigHandle = 0;118CSSM_DATA sig, in;119int fret = 0;120121if (padding != RSA_PKCS1_PADDING)122return -1;123124cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);125if(cret) abort();126127cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);128if(cret) abort();129130ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,131kSecCredentialTypeDefault, &creds);132if(ret) abort();133134ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,135creds, cssmKey, &sigHandle);136if(ret) abort();137138in.Data = (uint8 *)from;139in.Length = flen;140141sig.Data = (uint8 *)to;142sig.Length = kc->keysize;143144cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);145if(cret) {146/* cssmErrorString(cret); */147fret = -1;148} else149fret = sig.Length;150151if(sigHandle)152CSSM_DeleteContext(sigHandle);153154return fret;155}156157static int158kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,159RSA * rsa, int padding)160{161struct kc_rsa *kc = RSA_get_app_data(rsa);162163CSSM_RETURN cret;164OSStatus ret;165const CSSM_ACCESS_CREDENTIALS *creds;166SecKeyRef privKeyRef = (SecKeyRef)kc->item;167CSSM_CSP_HANDLE cspHandle;168const CSSM_KEY *cssmKey;169CSSM_CC_HANDLE handle = 0;170CSSM_DATA out, in, rem;171int fret = 0;172CSSM_SIZE outlen = 0;173char remdata[1024];174175if (padding != RSA_PKCS1_PADDING)176return -1;177178cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);179if(cret) abort();180181cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);182if(cret) abort();183184ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,185kSecCredentialTypeDefault, &creds);186if(ret) abort();187188189ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,190CSSM_ALGID_RSA,191creds,192cssmKey,193CSSM_PADDING_PKCS1,194&handle);195if(ret) abort();196197in.Data = (uint8 *)from;198in.Length = flen;199200out.Data = (uint8 *)to;201out.Length = kc->keysize;202203rem.Data = (uint8 *)remdata;204rem.Length = sizeof(remdata);205206cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);207if(cret) {208/* cssmErrorString(cret); */209fret = -1;210} else211fret = out.Length;212213if(handle)214CSSM_DeleteContext(handle);215216return fret;217}218219static int220kc_rsa_init(RSA *rsa)221{222return 1;223}224225static int226kc_rsa_finish(RSA *rsa)227{228struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);229CFRelease(kc_rsa->item);230memset(kc_rsa, 0, sizeof(*kc_rsa));231free(kc_rsa);232return 1;233}234235static const RSA_METHOD kc_rsa_pkcs1_method = {236"hx509 Keychain PKCS#1 RSA",237kc_rsa_public_encrypt,238kc_rsa_public_decrypt,239kc_rsa_private_encrypt,240kc_rsa_private_decrypt,241NULL,242NULL,243kc_rsa_init,244kc_rsa_finish,2450,246NULL,247NULL,248NULL249};250251static int252set_private_key(hx509_context context,253SecKeychainItemRef itemRef,254hx509_cert cert)255{256struct kc_rsa *kc;257hx509_private_key key;258RSA *rsa;259int ret;260261ret = hx509_private_key_init(&key, NULL, NULL);262if (ret)263return ret;264265kc = calloc(1, sizeof(*kc));266if (kc == NULL)267_hx509_abort("out of memory");268269kc->item = itemRef;270271rsa = RSA_new();272if (rsa == NULL)273_hx509_abort("out of memory");274275/* Argh, fake modulus since OpenSSL API is on crack */276{277SecKeychainAttributeList *attrs = NULL;278uint32_t size;279void *data;280281rsa->n = BN_new();282if (rsa->n == NULL) abort();283284ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);285if (ret) abort();286287size = *(uint32_t *)attrs->attr[0].data;288SecKeychainItemFreeAttributesAndData(attrs, NULL);289290kc->keysize = (size + 7) / 8;291292data = malloc(kc->keysize);293memset(data, 0xe0, kc->keysize);294BN_bin2bn(data, kc->keysize, rsa->n);295free(data);296}297rsa->e = NULL;298299RSA_set_method(rsa, &kc_rsa_pkcs1_method);300ret = RSA_set_app_data(rsa, kc);301if (ret != 1)302_hx509_abort("RSA_set_app_data");303304hx509_private_key_assign_rsa(key, rsa);305_hx509_cert_assign_key(cert, key);306307return 0;308}309310/*311*312*/313314struct ks_keychain {315int anchors;316SecKeychainRef keychain;317};318319static int320keychain_init(hx509_context context,321hx509_certs certs, void **data, int flags,322const char *residue, hx509_lock lock)323{324struct ks_keychain *ctx;325326ctx = calloc(1, sizeof(*ctx));327if (ctx == NULL) {328hx509_clear_error_string(context);329return ENOMEM;330}331332if (residue) {333if (strcasecmp(residue, "system-anchors") == 0) {334ctx->anchors = 1;335} else if (strncasecmp(residue, "FILE:", 5) == 0) {336OSStatus ret;337338ret = SecKeychainOpen(residue + 5, &ctx->keychain);339if (ret != noErr) {340hx509_set_error_string(context, 0, ENOENT,341"Failed to open %s", residue);342return ENOENT;343}344} else {345hx509_set_error_string(context, 0, ENOENT,346"Unknown subtype %s", residue);347return ENOENT;348}349}350351*data = ctx;352return 0;353}354355/*356*357*/358359static int360keychain_free(hx509_certs certs, void *data)361{362struct ks_keychain *ctx = data;363if (ctx->keychain)364CFRelease(ctx->keychain);365memset(ctx, 0, sizeof(*ctx));366free(ctx);367return 0;368}369370/*371*372*/373374struct iter {375hx509_certs certs;376void *cursor;377SecKeychainSearchRef searchRef;378};379380static int381keychain_iter_start(hx509_context context,382hx509_certs certs, void *data, void **cursor)383{384struct ks_keychain *ctx = data;385struct iter *iter;386387iter = calloc(1, sizeof(*iter));388if (iter == NULL) {389hx509_set_error_string(context, 0, ENOMEM, "out of memory");390return ENOMEM;391}392393if (ctx->anchors) {394CFArrayRef anchors;395int ret;396int i;397398ret = hx509_certs_init(context, "MEMORY:ks-file-create",3990, NULL, &iter->certs);400if (ret) {401free(iter);402return ret;403}404405ret = SecTrustCopyAnchorCertificates(&anchors);406if (ret != 0) {407hx509_certs_free(&iter->certs);408free(iter);409hx509_set_error_string(context, 0, ENOMEM,410"Can't get trust anchors from Keychain");411return ENOMEM;412}413for (i = 0; i < CFArrayGetCount(anchors); i++) {414SecCertificateRef cr;415hx509_cert cert;416CSSM_DATA cssm;417418cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);419420SecCertificateGetData(cr, &cssm);421422ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);423if (ret)424continue;425426ret = hx509_certs_add(context, iter->certs, cert);427hx509_cert_free(cert);428}429CFRelease(anchors);430}431432if (iter->certs) {433int ret;434ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);435if (ret) {436hx509_certs_free(&iter->certs);437free(iter);438return ret;439}440} else {441OSStatus ret;442443ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,444kSecCertificateItemClass,445NULL,446&iter->searchRef);447if (ret) {448free(iter);449hx509_set_error_string(context, 0, ret,450"Failed to start search for attributes");451return ENOMEM;452}453}454455*cursor = iter;456return 0;457}458459/*460*461*/462463static int464keychain_iter(hx509_context context,465hx509_certs certs, void *data, void *cursor, hx509_cert *cert)466{467SecKeychainAttributeList *attrs = NULL;468SecKeychainAttributeInfo attrInfo;469UInt32 attrFormat[1] = { 0 };470SecKeychainItemRef itemRef;471SecItemAttr item[1];472struct iter *iter = cursor;473OSStatus ret;474UInt32 len;475void *ptr = NULL;476477if (iter->certs)478return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);479480*cert = NULL;481482ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);483if (ret == errSecItemNotFound)484return 0;485else if (ret != 0)486return EINVAL;487488/*489* Pick out certificate and matching "keyid"490*/491492item[0] = kSecPublicKeyHashItemAttr;493494attrInfo.count = 1;495attrInfo.tag = item;496attrInfo.format = attrFormat;497498ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,499&attrs, &len, &ptr);500if (ret)501return EINVAL;502503ret = hx509_cert_init_data(context, ptr, len, cert);504if (ret)505goto out;506507/*508* Find related private key if there is one by looking at509* kSecPublicKeyHashItemAttr == kSecKeyLabel510*/511{512SecKeychainSearchRef search;513SecKeychainAttribute attrKeyid;514SecKeychainAttributeList attrList;515516attrKeyid.tag = kSecKeyLabel;517attrKeyid.length = attrs->attr[0].length;518attrKeyid.data = attrs->attr[0].data;519520attrList.count = 1;521attrList.attr = &attrKeyid;522523ret = SecKeychainSearchCreateFromAttributes(NULL,524CSSM_DL_DB_RECORD_PRIVATE_KEY,525&attrList,526&search);527if (ret) {528ret = 0;529goto out;530}531532ret = SecKeychainSearchCopyNext(search, &itemRef);533CFRelease(search);534if (ret == errSecItemNotFound) {535ret = 0;536goto out;537} else if (ret) {538ret = EINVAL;539goto out;540}541set_private_key(context, itemRef, *cert);542}543544out:545SecKeychainItemFreeAttributesAndData(attrs, ptr);546547return ret;548}549550/*551*552*/553554static int555keychain_iter_end(hx509_context context,556hx509_certs certs,557void *data,558void *cursor)559{560struct iter *iter = cursor;561562if (iter->certs) {563hx509_certs_end_seq(context, iter->certs, iter->cursor);564hx509_certs_free(&iter->certs);565} else {566CFRelease(iter->searchRef);567}568569memset(iter, 0, sizeof(*iter));570free(iter);571return 0;572}573574/*575*576*/577578struct hx509_keyset_ops keyset_keychain = {579"KEYCHAIN",5800,581keychain_init,582NULL,583keychain_free,584NULL,585NULL,586keychain_iter_start,587keychain_iter,588keychain_iter_end589};590591#endif /* HAVE_FRAMEWORK_SECURITY */592593/*594*595*/596597void598_hx509_ks_keychain_register(hx509_context context)599{600#ifdef HAVE_FRAMEWORK_SECURITY601_hx509_ks_register(context, &keyset_keychain);602#endif603}604605606