1/* 2 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * pkcs12SafeBag.cpp : internal representation of various kinds 25 * of P12 SafeBags 26 */ 27 28#include "pkcs12SafeBag.h" 29#include "pkcs12Debug.h" 30#include "pkcs12Utils.h" 31#include <string.h> 32#include <assert.h> 33#include <Security/Security.h> 34#include <Security/SecKeyPriv.h> 35#include <Security/SecAsn1Templates.h> 36#include <security_asn1/nssUtils.h> 37 38/* 39 * P12SafeBag, abstract superclass of all safe bags. 40 * 41 * Constructor for decoding. Attr may include friendlyName and localKeyId; 42 * It may also be empty or NULL. 43 */ 44P12SafeBag::P12SafeBag( 45 NSS_Attribute **attrs, // including friendlyName, etc. 46 SecNssCoder &coder) 47 : mBagAttrs(coder), 48 mCoder(coder) 49{ 50 mFriendlyName.Data = mLocalKeyId.Data = NULL; 51 mFriendlyName.Length = mLocalKeyId.Length = 0; 52 53 /* parse attrs into friendlyName, localKeyId, and generic attrs */ 54 unsigned numAttrs = nssArraySize((const void **)attrs); 55 for(unsigned dex=0; dex<numAttrs; dex++) { 56 NSS_Attribute *attr = attrs[dex]; 57 unsigned numValues = nssArraySize((const void**)attr->attrValue); 58 59 if(nssCompareCssmData(&attr->attrType, 60 &CSSMOID_PKCS9_FriendlyName)) { 61 /* 62 * BMP string (UniCode). Spec says only one legal value. 63 */ 64 if(numValues != 1) { 65 p12ErrorLog("FriendlyName with %u values\n", numValues); 66 /* but let's keep going if we can */ 67 if(numValues == 0) { 68 P12_THROW_DECODE; 69 } 70 } 71 if(mCoder.decodeItem(*attr->attrValue[0], 72 kSecAsn1BMPStringTemplate, &mFriendlyName)) { 73 p12ErrorLog("***Error decoding FriendlyName string\n"); 74 P12_THROW_DECODE; 75 } 76 } 77 else if(nssCompareCssmData(&attr->attrType, 78 &CSSMOID_PKCS9_LocalKeyId)) { 79 /* 80 * Octet string. Spec says only one legal value. 81 */ 82 if(numValues != 1) { 83 p12ErrorLog("LocalKeyId with %u values\n", numValues); 84 /* but let's keep going if we can */ 85 if(numValues == 0) { 86 P12_THROW_DECODE; 87 } 88 } 89 if(mCoder.decodeItem(*attr->attrValue[0], 90 kSecAsn1OctetStringTemplate, &mLocalKeyId)) { 91 p12ErrorLog("***Error decoding LocalKeyId\n"); 92 P12_THROW_DECODE; 93 } 94 } 95 else { 96 /* others */ 97 mBagAttrs.addAttr(*attr); 98 } 99 } 100} 101 102/* 103 * Constructor for encoding. All arguments except for the coder 104 * are optional. 105 */ 106P12SafeBag::P12SafeBag( 107 CFStringRef fname, 108 CFDataRef keyId, 109 P12BagAttrs *otherAttrs, // optional 110 SecNssCoder &coder) 111 : mBagAttrs(otherAttrs, coder), 112 mCoder(coder) 113{ 114 friendlyName(fname); 115 localKeyId(keyId); 116} 117 118P12SafeBag::~P12SafeBag() 119{ 120 /* nothing if everything we allocd is via mCoder */ 121} 122 123/* 124 * Setters in CF terms, used when constructing prior 125 * to encoding. 126 */ 127void P12SafeBag::friendlyName( 128 CFStringRef fname) 129{ 130 CFIndex len = 0; 131 132 if(fname != NULL) { 133 len = CFStringGetLength(fname); 134 } 135 if(len == 0) { 136 mFriendlyName.Data = NULL; 137 mFriendlyName.Length = 0; 138 return; 139 } 140 141 /* convert unicode to byte array */ 142 unsigned flen = (unsigned)(len * sizeof(UniChar)); 143 mCoder.allocItem(mFriendlyName, flen); 144 unsigned char *cp = mFriendlyName.Data; 145 for(CFIndex dex=0; dex<len; dex++) { 146 UniChar uc = CFStringGetCharacterAtIndex(fname, dex); 147 *cp++ = uc >> 8; 148 *cp++ = uc & 0xff; 149 } 150} 151 152void P12SafeBag::localKeyId( 153 CFDataRef keyId) 154{ 155 CFIndex len = 0; 156 157 if(keyId != NULL) { 158 len = CFDataGetLength(keyId); 159 } 160 if(len == 0) { 161 mLocalKeyId.Data = NULL; 162 mLocalKeyId.Length = 0; 163 return; 164 } 165 mCoder.allocItem(mLocalKeyId, len); 166 const UInt8 *cp = CFDataGetBytePtr(keyId); 167 memmove(mLocalKeyId.Data, cp, len); 168} 169 170/* 171 * Copy out all attrs in API form. All incoming ptrs 172 * are optional. 173 */ 174void P12SafeBag::copyAllAttrs( 175 CFStringRef *fName, 176 CFDataRef *keyId, 177 P12BagAttrs **bagAttrs) 178{ 179 if(fName) { 180 *fName = friendlyName(); 181 } 182 if(keyId) { 183 *keyId = localKeyId(); 184 } 185 if(bagAttrs) { 186 if(mBagAttrs.numAttrs()) { 187 /* make a copy of our bag attrs */ 188 P12BagAttrs *attrs = new P12BagAttrs(&mBagAttrs, mCoder); 189 *bagAttrs = attrs; 190 } 191 else { 192 *bagAttrs = NULL; 193 } 194 } 195} 196 197 198/* getters in CF terms - result is created and returned */ 199CFStringRef P12SafeBag::friendlyName() 200{ 201 if(mFriendlyName.Data == NULL) { 202 /* not present, no error */ 203 return NULL; 204 } 205 /* shouldn't have stored this if it's an odd number of bytes */ 206 assert((mFriendlyName.Length & 1) == 0); 207 208 /* convert byte array to unicode */ 209 unsigned long strLen = mFriendlyName.Length / 2; 210 UniChar *uc = (UniChar *)malloc(strLen * sizeof(UniChar)); 211 const uint8 *inp = mFriendlyName.Data; 212 UniChar *outp = uc; 213 while(inp < (mFriendlyName.Data + mFriendlyName.Length)) { 214 *outp = (((unsigned)inp[0]) << 8) | inp[1]; 215 outp++; 216 inp += 2; 217 } 218 CFStringRef cstr = CFStringCreateWithCharacters(NULL, uc, strLen); 219 free(uc); 220 return cstr; 221} 222 223CFDataRef P12SafeBag::localKeyId() 224{ 225 if(mLocalKeyId.Data == NULL) { 226 /* not present, no error */ 227 return NULL; 228 } 229 return CFDataCreate(NULL, (const UInt8 *)mLocalKeyId.Data, 230 mLocalKeyId.Length); 231} 232 233/* 234 * Get all attrs, including friendlyName and localKeyId, 235 * in preparation for encoding. 236 */ 237NSS_Attribute **P12SafeBag::getAllAttrs() 238{ 239 unsigned numAttrs = mBagAttrs.numAttrs(); 240 if(mFriendlyName.Data) { 241 numAttrs++; 242 } 243 if(mLocalKeyId.Data) { 244 numAttrs++; 245 } 246 NSS_Attribute **attrs = 247 (NSS_Attribute **)p12NssNullArray(numAttrs, mCoder); 248 unsigned outDex=0; 249 for(unsigned i=0; i<mBagAttrs.numAttrs(); i++) { 250 attrs[outDex++] = mBagAttrs.getAttr(i); 251 } 252 if(mFriendlyName.Data) { 253 CSSM_DATA berName = {0, NULL}; 254 if(mCoder.encodeItem(&mFriendlyName, kSecAsn1BMPStringTemplate, 255 berName)) { 256 p12ErrorLog("***Error encoding FriendlyName string\n"); 257 P12_THROW_ENCODE; 258 } 259 attrs[outDex++] = makeAttr(CSSMOID_PKCS9_FriendlyName, 260 berName); 261 } 262 if(mLocalKeyId.Data) { 263 CSSM_DATA berName = {0, NULL}; 264 if(mCoder.encodeItem(&mLocalKeyId, kSecAsn1OctetStringTemplate, 265 berName)) { 266 p12ErrorLog("***Error encoding LocalKeyId string\n"); 267 P12_THROW_ENCODE; 268 } 269 attrs[outDex++] = makeAttr(CSSMOID_PKCS9_LocalKeyId, 270 berName); 271 } 272 assert(outDex == numAttrs); 273 return attrs; 274} 275 276/* 277 * Create an NSS_Attribute * for friendlyName or keyId 278 */ 279NSS_Attribute *P12SafeBag::makeAttr( 280 const CSSM_OID &attrId, 281 const CSSM_DATA &attrValue) 282{ 283 NSS_Attribute *attr = mCoder.mallocn<NSS_Attribute>(); 284 mCoder.allocCopyItem(attrId, attr->attrType); 285 attr->attrValue = mCoder.mallocn<CSSM_DATA *>(2); 286 attr->attrValue[0] = mCoder.mallocn<CSSM_DATA>(); 287 attr->attrValue[1] = NULL; 288 mCoder.allocCopyItem(attrValue, *attr->attrValue[0]); 289 return attr; 290} 291 292/* 293 * Individual bag types 294 */ 295 296/* decode */ 297P12CertBag::P12CertBag( 298 NSS_P12_CertBagType certType, // CT_X509, CT_SDSI 299 CSSM_DATA &certData, 300 NSS_Attribute **attrs, // optional 301 SecNssCoder &coder) 302 : P12SafeBag(attrs, coder), 303 mCertType(certType), 304 mCertRef(NULL) 305{ 306 coder.allocCopyItem(certData, mCertData); 307} 308 309/* encode */ 310P12CertBag::P12CertBag( 311 NSS_P12_CertBagType certType, // CT_X509, CT_SDSI 312 CSSM_DATA &certData, 313 CFStringRef fname, 314 CFDataRef keyId, 315 P12BagAttrs *otherAttrs, 316 SecNssCoder &coder) 317 : P12SafeBag(fname, keyId, otherAttrs, coder), 318 mCertType(certType), 319 mCertRef(NULL) 320{ 321 coder.allocCopyItem(certData, mCertData); 322} 323 324P12CertBag::~P12CertBag() 325{ 326 if(mCertRef) { 327 CFRelease(mCertRef); 328 } 329 /* everything else we allocd is via mCoder */ 330} 331 332/* convert to P12CertBag to SecCertificateRef */ 333SecCertificateRef P12CertBag::getSecCert() 334{ 335 if(mCertRef) { 336 CFRetain(mCertRef); /* a ref count for the caller */ 337 return mCertRef; 338 } 339 340 /* lazy creation... */ 341 CSSM_CERT_TYPE certType; 342 CSSM_CERT_ENCODING certEncoding; 343 switch(mCertType) { 344 case CT_X509: 345 certType = CSSM_CERT_X_509v3; 346 certEncoding = CSSM_CERT_ENCODING_DER; 347 break; 348 case CT_SDSI: 349 certType = CSSM_CERT_SDSIv1; 350 /* it's base64 encoded - no value for that in this enum */ 351 certEncoding = CSSM_CERT_ENCODING_UNKNOWN; 352 break; 353 default: 354 /* shouldn't currently happen, but... */ 355 certType = CSSM_CERT_UNKNOWN; 356 certEncoding = CSSM_CERT_ENCODING_UNKNOWN; 357 break; 358 } 359 OSStatus ortn = SecCertificateCreateFromData( 360 &mCertData, 361 certType, 362 certEncoding, 363 &mCertRef); 364 if(ortn) { 365 MacOSError::throwMe(ortn); 366 } 367 368 /* One ref count for us, one for the caller */ 369 CFRetain(mCertRef); 370 return mCertRef; 371} 372 373P12CrlBag::P12CrlBag( 374 NSS_P12_CrlBagType crlType, // CRT_X509, only for now 375 CSSM_DATA &crlData, 376 NSS_Attribute **attrs, // optional 377 SecNssCoder &coder) 378 : P12SafeBag(attrs, coder), 379 mCrlType(crlType) 380{ 381 coder.allocCopyItem(crlData, mCrlData); 382} 383 384P12CrlBag::P12CrlBag( 385 NSS_P12_CrlBagType crlType, // CRT_X509, only for now 386 CFDataRef crlData, 387 CFStringRef fname, 388 CFDataRef keyId, 389 P12BagAttrs *otherAttrs, 390 SecNssCoder &coder) 391 : P12SafeBag(fname, keyId, otherAttrs, coder), 392 mCrlType(crlType) 393{ 394 coder.allocCopyItem(CFDataGetBytePtr(crlData), 395 CFDataGetLength(crlData), mCrlData); 396} 397 398P12CrlBag::~P12CrlBag() 399{ 400 /* nothing if everything we allocd is via mCoder */ 401} 402 403/* 404 * For decode - both shrouded and plain. 405 * On decode, we own the key and will do the CSSM_FreeKey in 406 * our destructor. Caller owns the actual CSSM_KEY memory. 407 */ 408P12KeyBag::P12KeyBag( 409 CSSM_KEY_PTR key, 410 CSSM_CSP_HANDLE cspHand, 411 NSS_Attribute **attrs, // optional 412 CSSM_DATA &labelData, 413 SecNssCoder &coder) 414 : P12SafeBag(attrs, coder), 415 mKey(key), 416 mCspHand(cspHand), 417 mKeyRef(NULL), 418 mWeOwnKey(true), 419 mPrivKeyCreds(NULL), 420 mDupKey(false) 421{ 422 setLabel(labelData); 423} 424 425/* for encode - app owns CSSM_KEY */ 426P12KeyBag::P12KeyBag( 427 const CSSM_KEY *key, 428 CSSM_CSP_HANDLE cspHand, 429 CFStringRef fname, 430 CFDataRef keyId, 431 P12BagAttrs *otherAttrs, 432 SecNssCoder &coder, 433 SecKeyRef keyRef /* = NULL */) 434 435 : P12SafeBag(fname, keyId, otherAttrs, coder), 436 mKey((CSSM_KEY_PTR)key), 437 mCspHand(cspHand), 438 mKeyRef(keyRef), 439 mWeOwnKey(false), // app giveth, app taketh away 440 mPrivKeyCreds(NULL), 441 mDupKey(false) 442{ 443 if(mKeyRef) { 444 CFRetain(mKeyRef); 445 /* 446 * Get creds associated with this key 447 */ 448 OSStatus ortn = SecKeyGetCredentials(mKeyRef, 449 CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, 450 kSecCredentialTypeDefault, 451 &mPrivKeyCreds); 452 if(ortn) { 453 p12LogCssmError("SecKeyGetCredentials", ortn); 454 MacOSError::throwMe(ortn); 455 } 456 } 457 mLabel.Data = NULL; 458 mLabel.Length = 0; 459} 460 461 462P12KeyBag::~P12KeyBag() 463{ 464 freeKey(); 465} 466 467void P12KeyBag::setLabel( 468 const CSSM_DATA &newLabel) 469{ 470 mCoder.allocCopyItem(newLabel, mLabel); 471} 472 473/* reusable key setter */ 474void P12KeyBag::setKey( 475 CSSM_KEY_PTR cssmKey) 476{ 477 freeKey(); 478 mKey = cssmKey; 479} 480 481void P12KeyBag::freeKey() 482{ 483 if(mWeOwnKey) { 484 assert(mKey != NULL); 485 assert(mCspHand != 0); 486 CSSM_FreeKey(mCspHand, NULL, mKey, CSSM_FALSE); 487 } 488 mKey = NULL; 489 if(mKeyRef) { 490 CFRelease(mKeyRef); 491 mKeyRef = NULL; 492 } 493} 494 495/* 496 * Others we don't implement 497 */ 498P12OpaqueBag::P12OpaqueBag( 499 const CSSM_OID &oid, 500 const CSSM_DATA &blob, 501 NSS_Attribute **attrs, // optional 502 SecNssCoder &coder) 503 : P12SafeBag(attrs, coder) 504{ 505 coder.allocCopyItem(oid, mOid); 506 coder.allocCopyItem(blob, mBlob); 507} 508 509P12OpaqueBag::P12OpaqueBag( 510 CFDataRef oid, 511 CFDataRef blob, 512 CFStringRef fname, 513 CFDataRef keyId, 514 P12BagAttrs *otherAttrs, 515 SecNssCoder &coder) 516 : P12SafeBag(fname, keyId, otherAttrs, coder) 517{ 518 coder.allocCopyItem(CFDataGetBytePtr(oid), 519 CFDataGetLength(oid), mOid); 520 coder.allocCopyItem(CFDataGetBytePtr(blob), 521 CFDataGetLength(blob), mBlob); 522} 523 524P12OpaqueBag::~P12OpaqueBag() 525{ 526 /* nothing if everything we allocd is via mCoder */ 527} 528 529