]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | */ | |
44 | P12SafeBag::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 | */ | |
106 | P12SafeBag::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 | ||
118 | P12SafeBag::~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 | */ | |
127 | void 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 = 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 | ||
152 | void 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 | */ | |
174 | void 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 */ | |
199 | CFStringRef 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 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 | ||
223 | CFDataRef 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 | */ | |
237 | NSS_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 | */ | |
279 | NSS_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 */ | |
297 | P12CertBag::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 */ | |
310 | P12CertBag::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 | ||
324 | P12CertBag::~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 */ | |
333 | SecCertificateRef 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 | ||
373 | P12CrlBag::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 | ||
384 | P12CrlBag::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 | ||
398 | P12CrlBag::~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 | */ | |
408 | P12KeyBag::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 */ | |
426 | P12KeyBag::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 | ||
462 | P12KeyBag::~P12KeyBag() | |
463 | { | |
464 | freeKey(); | |
465 | } | |
466 | ||
467 | void P12KeyBag::setLabel( | |
468 | const CSSM_DATA &newLabel) | |
469 | { | |
470 | mCoder.allocCopyItem(newLabel, mLabel); | |
471 | } | |
472 | ||
473 | /* reusable key setter */ | |
474 | void P12KeyBag::setKey( | |
475 | CSSM_KEY_PTR cssmKey) | |
476 | { | |
477 | freeKey(); | |
478 | mKey = cssmKey; | |
479 | } | |
480 | ||
481 | void 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 | */ | |
498 | P12OpaqueBag::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 | ||
509 | P12OpaqueBag::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 | ||
524 | P12OpaqueBag::~P12OpaqueBag() | |
525 | { | |
526 | /* nothing if everything we allocd is via mCoder */ | |
527 | } | |
528 |