root/source4/heimdal/lib/hx509/ks_keychain.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. getAttribute
  2. kc_rsa_public_encrypt
  3. kc_rsa_public_decrypt
  4. kc_rsa_private_encrypt
  5. kc_rsa_private_decrypt
  6. kc_rsa_init
  7. kc_rsa_finish
  8. set_private_key
  9. keychain_init
  10. keychain_free
  11. keychain_iter_start
  12. keychain_iter
  13. keychain_iter_end
  14. _hx509_ks_keychain_register

   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 RCSID("$Id$");
  36 
  37 #ifdef HAVE_FRAMEWORK_SECURITY
  38 
  39 #include <Security/Security.h>
  40 
  41 /* Missing function decls in pre Leopard */
  42 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO
  43 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
  44 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
  45                               int, const CSSM_ACCESS_CREDENTIALS **);
  46 #define kSecCredentialTypeDefault 0
  47 #endif
  48 
  49 
  50 static int
  51 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
     /* [<][>][^][v][top][bottom][index][help] */
  52              SecKeychainAttributeList **attrs)
  53 {       
  54     SecKeychainAttributeInfo attrInfo;
  55     UInt32 attrFormat = 0;
  56     OSStatus ret;
  57 
  58     *attrs = NULL;
  59 
  60     attrInfo.count = 1;
  61     attrInfo.tag = &item;
  62     attrInfo.format = &attrFormat;
  63 
  64     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
  65                                                attrs, NULL, NULL);
  66     if (ret)
  67         return EINVAL;
  68     return 0;
  69 }
  70 
  71 
  72 /*
  73  *
  74  */
  75 
  76 struct kc_rsa {
  77     SecKeychainItemRef item;
  78     size_t keysize;
  79 };
  80 
  81 
  82 static int
  83 kc_rsa_public_encrypt(int flen,
     /* [<][>][^][v][top][bottom][index][help] */
  84                       const unsigned char *from,
  85                       unsigned char *to,
  86                       RSA *rsa,
  87                       int padding)
  88 {
  89     return -1;
  90 }
  91 
  92 static int
  93 kc_rsa_public_decrypt(int flen,
     /* [<][>][^][v][top][bottom][index][help] */
  94                       const unsigned char *from,
  95                       unsigned char *to,
  96                       RSA *rsa,
  97                       int padding)
  98 {
  99     return -1;
 100 }
 101 
 102 
 103 static int
 104 kc_rsa_private_encrypt(int flen,
     /* [<][>][^][v][top][bottom][index][help] */
 105                        const unsigned char *from,
 106                        unsigned char *to,
 107                        RSA *rsa,
 108                        int padding)
 109 {
 110     struct kc_rsa *kc = RSA_get_app_data(rsa);
 111 
 112     CSSM_RETURN cret;
 113     OSStatus ret;
 114     const CSSM_ACCESS_CREDENTIALS *creds;
 115     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
 116     CSSM_CSP_HANDLE cspHandle;
 117     const CSSM_KEY *cssmKey;
 118     CSSM_CC_HANDLE sigHandle = 0;
 119     CSSM_DATA sig, in;
 120     int fret = 0;
 121 
 122 
 123     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
 124     if(cret) abort();
 125 
 126     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
 127     if(cret) abort();
 128 
 129     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
 130                                kSecCredentialTypeDefault, &creds);
 131     if(ret) abort();
 132 
 133     ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
 134                                           creds, cssmKey, &sigHandle);
 135     if(ret) abort();
 136 
 137     in.Data = (uint8 *)from;
 138     in.Length = flen;
 139         
 140     sig.Data = (uint8 *)to;
 141     sig.Length = kc->keysize;
 142         
 143     cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
 144     if(cret) {
 145         /* cssmErrorString(cret); */
 146         fret = -1;
 147     } else
 148         fret = sig.Length;
 149 
 150     if(sigHandle)
 151         CSSM_DeleteContext(sigHandle);
 152 
 153     return fret;
 154 }
 155 
 156 static int
 157 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
     /* [<][>][^][v][top][bottom][index][help] */
 158                        RSA * rsa, int padding)
 159 {
 160     return -1;
 161 }
 162 
 163 static int
 164 kc_rsa_init(RSA *rsa)
     /* [<][>][^][v][top][bottom][index][help] */
 165 {
 166     return 1;
 167 }
 168 
 169 static int
 170 kc_rsa_finish(RSA *rsa)
     /* [<][>][^][v][top][bottom][index][help] */
 171 {
 172     struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
 173     CFRelease(kc_rsa->item);
 174     memset(kc_rsa, 0, sizeof(*kc_rsa));
 175     free(kc_rsa);
 176     return 1;
 177 }
 178 
 179 static const RSA_METHOD kc_rsa_pkcs1_method = {
 180     "hx509 Keychain PKCS#1 RSA",
 181     kc_rsa_public_encrypt,
 182     kc_rsa_public_decrypt,
 183     kc_rsa_private_encrypt,
 184     kc_rsa_private_decrypt,
 185     NULL,
 186     NULL,
 187     kc_rsa_init,
 188     kc_rsa_finish,
 189     0,
 190     NULL,
 191     NULL,
 192     NULL
 193 };
 194 
 195 static int
 196 set_private_key(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 197                 SecKeychainItemRef itemRef,
 198                 hx509_cert cert)
 199 {
 200     struct kc_rsa *kc;
 201     hx509_private_key key;
 202     RSA *rsa;
 203     int ret;
 204 
 205     ret = _hx509_private_key_init(&key, NULL, NULL);
 206     if (ret)
 207         return ret;
 208 
 209     kc = calloc(1, sizeof(*kc));
 210     if (kc == NULL)
 211         _hx509_abort("out of memory");
 212 
 213     kc->item = itemRef;
 214 
 215     rsa = RSA_new();
 216     if (rsa == NULL)
 217         _hx509_abort("out of memory");
 218 
 219     /* Argh, fake modulus since OpenSSL API is on crack */
 220     {
 221         SecKeychainAttributeList *attrs = NULL;
 222         uint32_t size;
 223         void *data;
 224 
 225         rsa->n = BN_new();
 226         if (rsa->n == NULL) abort();
 227 
 228         ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
 229         if (ret) abort();
 230 
 231         size = *(uint32_t *)attrs->attr[0].data;
 232         SecKeychainItemFreeAttributesAndData(attrs, NULL);
 233 
 234         kc->keysize = (size + 7) / 8;
 235 
 236         data = malloc(kc->keysize);
 237         memset(data, 0xe0, kc->keysize);
 238         BN_bin2bn(data, kc->keysize, rsa->n);
 239         free(data);
 240     }
 241     rsa->e = NULL;
 242 
 243     RSA_set_method(rsa, &kc_rsa_pkcs1_method);
 244     ret = RSA_set_app_data(rsa, kc);
 245     if (ret != 1)
 246         _hx509_abort("RSA_set_app_data");
 247 
 248     _hx509_private_key_assign_rsa(key, rsa);
 249     _hx509_cert_assign_key(cert, key);
 250 
 251     return 0;
 252 }
 253 
 254 /*
 255  *
 256  */
 257 
 258 struct ks_keychain {
 259     int anchors;
 260     SecKeychainRef keychain;
 261 };
 262 
 263 static int
 264 keychain_init(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 265               hx509_certs certs, void **data, int flags,
 266               const char *residue, hx509_lock lock)
 267 {
 268     struct ks_keychain *ctx;
 269 
 270     ctx = calloc(1, sizeof(*ctx));
 271     if (ctx == NULL) {
 272         hx509_clear_error_string(context);
 273         return ENOMEM;
 274     }
 275 
 276     if (residue) {
 277         if (strcasecmp(residue, "system-anchors") == 0) {
 278             ctx->anchors = 1;
 279         } else if (strncasecmp(residue, "FILE:", 5) == 0) {
 280             OSStatus ret;
 281 
 282             ret = SecKeychainOpen(residue + 5, &ctx->keychain);
 283             if (ret != noErr) {
 284                 hx509_set_error_string(context, 0, ENOENT,
 285                                        "Failed to open %s", residue);
 286                 return ENOENT;
 287             }
 288         } else {
 289             hx509_set_error_string(context, 0, ENOENT,
 290                                    "Unknown subtype %s", residue);
 291             return ENOENT;
 292         }
 293     }
 294 
 295     *data = ctx;
 296     return 0;
 297 }
 298 
 299 /*
 300  *
 301  */
 302 
 303 static int
 304 keychain_free(hx509_certs certs, void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 305 {
 306     struct ks_keychain *ctx = data;
 307     if (ctx->keychain)
 308         CFRelease(ctx->keychain);
 309     memset(ctx, 0, sizeof(*ctx));
 310     free(ctx);
 311     return 0;
 312 }
 313 
 314 /*
 315  *
 316  */
 317 
 318 struct iter {
 319     hx509_certs certs;
 320     void *cursor;
 321     SecKeychainSearchRef searchRef;
 322 };
 323 
 324 static int
 325 keychain_iter_start(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 326                     hx509_certs certs, void *data, void **cursor)
 327 {
 328     struct ks_keychain *ctx = data;
 329     struct iter *iter;
 330 
 331     iter = calloc(1, sizeof(*iter));
 332     if (iter == NULL) {
 333         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 334         return ENOMEM;
 335     }
 336 
 337     if (ctx->anchors) {
 338         CFArrayRef anchors;
 339         int ret;
 340         int i;
 341 
 342         ret = hx509_certs_init(context, "MEMORY:ks-file-create",
 343                                0, NULL, &iter->certs);
 344         if (ret) {
 345             free(iter);
 346             return ret;
 347         }
 348 
 349         ret = SecTrustCopyAnchorCertificates(&anchors);
 350         if (ret != 0) {
 351             hx509_certs_free(&iter->certs);
 352             free(iter);
 353             hx509_set_error_string(context, 0, ENOMEM,
 354                                    "Can't get trust anchors from Keychain");
 355             return ENOMEM;
 356         }
 357         for (i = 0; i < CFArrayGetCount(anchors); i++) {
 358             SecCertificateRef cr;
 359             hx509_cert cert;
 360             CSSM_DATA cssm;
 361 
 362             cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
 363 
 364             SecCertificateGetData(cr, &cssm);
 365 
 366             ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
 367             if (ret)
 368                 continue;
 369 
 370             ret = hx509_certs_add(context, iter->certs, cert);
 371             hx509_cert_free(cert);
 372         }
 373         CFRelease(anchors);
 374     }
 375 
 376     if (iter->certs) {
 377         int ret;
 378         ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
 379         if (ret) {
 380             hx509_certs_free(&iter->certs);
 381             free(iter);
 382             return ret;
 383         }
 384     } else {
 385         OSStatus ret;
 386 
 387         ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
 388                                                     kSecCertificateItemClass,
 389                                                     NULL,
 390                                                     &iter->searchRef);
 391         if (ret) {
 392             free(iter);
 393             hx509_set_error_string(context, 0, ret,
 394                                    "Failed to start search for attributes");
 395             return ENOMEM;
 396         }
 397     }
 398 
 399     *cursor = iter;
 400     return 0;
 401 }
 402 
 403 /*
 404  *
 405  */
 406 
 407 static int
 408 keychain_iter(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 409               hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
 410 {
 411     SecKeychainAttributeList *attrs = NULL;
 412     SecKeychainAttributeInfo attrInfo;
 413     UInt32 attrFormat[1] = { 0 };
 414     SecKeychainItemRef itemRef;
 415     SecItemAttr item[1];
 416     struct iter *iter = cursor;
 417     OSStatus ret;
 418     UInt32 len;
 419     void *ptr = NULL;
 420 
 421     if (iter->certs)
 422         return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
 423 
 424     *cert = NULL;
 425 
 426     ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
 427     if (ret == errSecItemNotFound)
 428         return 0;
 429     else if (ret != 0)
 430         return EINVAL;
 431         
 432     /*
 433      * Pick out certificate and matching "keyid"
 434      */
 435 
 436     item[0] = kSecPublicKeyHashItemAttr;
 437 
 438     attrInfo.count = 1;
 439     attrInfo.tag = item;
 440     attrInfo.format = attrFormat;
 441 
 442     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
 443                                                &attrs, &len, &ptr);
 444     if (ret)
 445         return EINVAL;
 446 
 447     ret = hx509_cert_init_data(context, ptr, len, cert);
 448     if (ret)
 449         goto out;
 450 
 451     /*
 452      * Find related private key if there is one by looking at
 453      * kSecPublicKeyHashItemAttr == kSecKeyLabel
 454      */
 455     {
 456         SecKeychainSearchRef search;
 457         SecKeychainAttribute attrKeyid;
 458         SecKeychainAttributeList attrList;
 459 
 460         attrKeyid.tag = kSecKeyLabel;
 461         attrKeyid.length = attrs->attr[0].length;
 462         attrKeyid.data = attrs->attr[0].data;
 463         
 464         attrList.count = 1;
 465         attrList.attr = &attrKeyid;
 466 
 467         ret = SecKeychainSearchCreateFromAttributes(NULL,
 468                                                     CSSM_DL_DB_RECORD_PRIVATE_KEY,
 469                                                     &attrList,
 470                                                     &search);
 471         if (ret) {
 472             ret = 0;
 473             goto out;
 474         }
 475 
 476         ret = SecKeychainSearchCopyNext(search, &itemRef);
 477         CFRelease(search);
 478         if (ret == errSecItemNotFound) {
 479             ret = 0;
 480             goto out;
 481         } else if (ret) {
 482             ret = EINVAL;
 483             goto out;
 484         }
 485         set_private_key(context, itemRef, *cert);
 486     }
 487 
 488 out:
 489     SecKeychainItemFreeAttributesAndData(attrs, ptr);
 490 
 491     return ret;
 492 }
 493 
 494 /*
 495  *
 496  */
 497 
 498 static int
 499 keychain_iter_end(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 500                   hx509_certs certs,
 501                   void *data,
 502                   void *cursor)
 503 {
 504     struct iter *iter = cursor;
 505 
 506     if (iter->certs) {
 507         int ret;
 508         ret = hx509_certs_end_seq(context, iter->certs, iter->cursor);
 509         hx509_certs_free(&iter->certs);
 510     } else {
 511         CFRelease(iter->searchRef);
 512     }
 513 
 514     memset(iter, 0, sizeof(*iter));
 515     free(iter);
 516     return 0;
 517 }
 518 
 519 /*
 520  *
 521  */
 522 
 523 struct hx509_keyset_ops keyset_keychain = {
 524     "KEYCHAIN",
 525     0,
 526     keychain_init,
 527     NULL,
 528     keychain_free,
 529     NULL,
 530     NULL,
 531     keychain_iter_start,
 532     keychain_iter,
 533     keychain_iter_end
 534 };
 535 
 536 #endif /* HAVE_FRAMEWORK_SECURITY */
 537 
 538 /*
 539  *
 540  */
 541 
 542 void
 543 _hx509_ks_keychain_register(hx509_context context)
     /* [<][>][^][v][top][bottom][index][help] */
 544 {
 545 #ifdef HAVE_FRAMEWORK_SECURITY
 546     _hx509_ks_register(context, &keyset_keychain);
 547 #endif
 548 }

/* [<][>][^][v][top][bottom][index][help] */