Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/softoken/legacydb/lowcert.c @ 3:150b72113545
Add DBM and legacydb support
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 05 Aug 2014 18:32:02 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2:a945361df361 | 3:150b72113545 |
---|---|
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 | |
5 /* | |
6 * Certificate handling code | |
7 */ | |
8 | |
9 #include "seccomon.h" | |
10 #include "secder.h" | |
11 #include "nssilock.h" | |
12 #include "lowkeyi.h" | |
13 #include "secasn1.h" | |
14 #include "secoid.h" | |
15 #include "secerr.h" | |
16 #include "pcert.h" | |
17 | |
18 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) | |
19 | |
20 static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = { | |
21 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) }, | |
22 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
23 offsetof(NSSLOWCERTSubjectPublicKeyInfo,algorithm), | |
24 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
25 { SEC_ASN1_BIT_STRING, | |
26 offsetof(NSSLOWCERTSubjectPublicKeyInfo,subjectPublicKey), }, | |
27 { 0, } | |
28 }; | |
29 | |
30 static const SEC_ASN1Template nsslowcert_RSAPublicKeyTemplate[] = { | |
31 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) }, | |
32 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.modulus), }, | |
33 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.publicExponent), }, | |
34 { 0, } | |
35 }; | |
36 static const SEC_ASN1Template nsslowcert_DSAPublicKeyTemplate[] = { | |
37 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dsa.publicValue), }, | |
38 { 0, } | |
39 }; | |
40 static const SEC_ASN1Template nsslowcert_DHPublicKeyTemplate[] = { | |
41 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dh.publicValue), }, | |
42 { 0, } | |
43 }; | |
44 | |
45 /* | |
46 * See bugzilla bug 125359 | |
47 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, | |
48 * all of the templates above that en/decode into integers must be converted | |
49 * from ASN.1's signed integer type. This is done by marking either the | |
50 * source or destination (encoding or decoding, respectively) type as | |
51 * siUnsignedInteger. | |
52 */ | |
53 | |
54 static void | |
55 prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) | |
56 { | |
57 pubk->u.rsa.modulus.type = siUnsignedInteger; | |
58 pubk->u.rsa.publicExponent.type = siUnsignedInteger; | |
59 } | |
60 | |
61 static void | |
62 prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) | |
63 { | |
64 pubk->u.dsa.publicValue.type = siUnsignedInteger; | |
65 pubk->u.dsa.params.prime.type = siUnsignedInteger; | |
66 pubk->u.dsa.params.subPrime.type = siUnsignedInteger; | |
67 pubk->u.dsa.params.base.type = siUnsignedInteger; | |
68 } | |
69 | |
70 static void | |
71 prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) | |
72 { | |
73 pubk->u.dh.prime.type = siUnsignedInteger; | |
74 pubk->u.dh.base.type = siUnsignedInteger; | |
75 pubk->u.dh.publicValue.type = siUnsignedInteger; | |
76 } | |
77 | |
78 /* | |
79 * simple cert decoder to avoid the cost of asn1 engine | |
80 */ | |
81 static unsigned char * | |
82 nsslowcert_dataStart(unsigned char *buf, unsigned int length, | |
83 unsigned int *data_length, PRBool includeTag, | |
84 unsigned char* rettag) { | |
85 unsigned char tag; | |
86 unsigned int used_length= 0; | |
87 | |
88 /* need at least a tag and a 1 byte length */ | |
89 if (length < 2) { | |
90 return NULL; | |
91 } | |
92 | |
93 tag = buf[used_length++]; | |
94 | |
95 if (rettag) { | |
96 *rettag = tag; | |
97 } | |
98 | |
99 /* blow out when we come to the end */ | |
100 if (tag == 0) { | |
101 return NULL; | |
102 } | |
103 | |
104 *data_length = buf[used_length++]; | |
105 | |
106 if (*data_length&0x80) { | |
107 int len_count = *data_length & 0x7f; | |
108 | |
109 if (len_count+used_length > length) { | |
110 return NULL; | |
111 } | |
112 | |
113 *data_length = 0; | |
114 | |
115 while (len_count-- > 0) { | |
116 *data_length = (*data_length << 8) | buf[used_length++]; | |
117 } | |
118 } | |
119 | |
120 if (*data_length > (length-used_length) ) { | |
121 *data_length = length-used_length; | |
122 return NULL; | |
123 } | |
124 if (includeTag) *data_length += used_length; | |
125 | |
126 return (buf + (includeTag ? 0 : used_length)); | |
127 } | |
128 | |
129 static void SetTimeType(SECItem* item, unsigned char tagtype) | |
130 { | |
131 switch (tagtype) { | |
132 case SEC_ASN1_UTC_TIME: | |
133 item->type = siUTCTime; | |
134 break; | |
135 | |
136 case SEC_ASN1_GENERALIZED_TIME: | |
137 item->type = siGeneralizedTime; | |
138 break; | |
139 | |
140 default: | |
141 PORT_Assert(0); | |
142 break; | |
143 } | |
144 } | |
145 | |
146 static int | |
147 nsslowcert_GetValidityFields(unsigned char *buf,int buf_length, | |
148 SECItem *notBefore, SECItem *notAfter) | |
149 { | |
150 unsigned char tagtype; | |
151 notBefore->data = nsslowcert_dataStart(buf,buf_length, | |
152 ¬Before->len,PR_FALSE, &tagtype); | |
153 if (notBefore->data == NULL) return SECFailure; | |
154 SetTimeType(notBefore, tagtype); | |
155 buf_length -= (notBefore->data-buf) + notBefore->len; | |
156 buf = notBefore->data + notBefore->len; | |
157 notAfter->data = nsslowcert_dataStart(buf,buf_length, | |
158 ¬After->len,PR_FALSE, &tagtype); | |
159 if (notAfter->data == NULL) return SECFailure; | |
160 SetTimeType(notAfter, tagtype); | |
161 return SECSuccess; | |
162 } | |
163 | |
164 static int | |
165 nsslowcert_GetCertFields(unsigned char *cert,int cert_length, | |
166 SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject, | |
167 SECItem *valid, SECItem *subjkey, SECItem *extensions) | |
168 { | |
169 unsigned char *buf; | |
170 unsigned int buf_length; | |
171 unsigned char *dummy; | |
172 unsigned int dummylen; | |
173 | |
174 /* get past the signature wrap */ | |
175 buf = nsslowcert_dataStart(cert,cert_length,&buf_length,PR_FALSE, NULL); | |
176 if (buf == NULL) return SECFailure; | |
177 /* get into the raw cert data */ | |
178 buf = nsslowcert_dataStart(buf,buf_length,&buf_length,PR_FALSE, NULL); | |
179 if (buf == NULL) return SECFailure; | |
180 /* skip past any optional version number */ | |
181 if ((buf[0] & 0xa0) == 0xa0) { | |
182 dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL); | |
183 if (dummy == NULL) return SECFailure; | |
184 buf_length -= (dummy-buf) + dummylen; | |
185 buf = dummy + dummylen; | |
186 } | |
187 /* serial number */ | |
188 if (derSN) { | |
189 derSN->data=nsslowcert_dataStart(buf,buf_length,&derSN->len,PR_TRUE, NULL); | |
190 /* derSN->data doesn't need to be checked because if it fails so will | |
191 * serial->data below. The only difference between the two calls is | |
192 * whether or not the tags are included in the returned buffer */ | |
193 } | |
194 serial->data = nsslowcert_dataStart(buf,buf_length,&serial->len,PR_FALSE, NULL); | |
195 if (serial->data == NULL) return SECFailure; | |
196 buf_length -= (serial->data-buf) + serial->len; | |
197 buf = serial->data + serial->len; | |
198 /* skip the OID */ | |
199 dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL); | |
200 if (dummy == NULL) return SECFailure; | |
201 buf_length -= (dummy-buf) + dummylen; | |
202 buf = dummy + dummylen; | |
203 /* issuer */ | |
204 issuer->data = nsslowcert_dataStart(buf,buf_length,&issuer->len,PR_TRUE, NULL); | |
205 if (issuer->data == NULL) return SECFailure; | |
206 buf_length -= (issuer->data-buf) + issuer->len; | |
207 buf = issuer->data + issuer->len; | |
208 | |
209 /* only wanted issuer/SN */ | |
210 if (valid == NULL) { | |
211 return SECSuccess; | |
212 } | |
213 /* validity */ | |
214 valid->data = nsslowcert_dataStart(buf,buf_length,&valid->len,PR_FALSE, NULL); | |
215 if (valid->data == NULL) return SECFailure; | |
216 buf_length -= (valid->data-buf) + valid->len; | |
217 buf = valid->data + valid->len; | |
218 /*subject */ | |
219 subject->data=nsslowcert_dataStart(buf,buf_length,&subject->len,PR_TRUE, NULL); | |
220 if (subject->data == NULL) return SECFailure; | |
221 buf_length -= (subject->data-buf) + subject->len; | |
222 buf = subject->data + subject->len; | |
223 /* subject key info */ | |
224 subjkey->data=nsslowcert_dataStart(buf,buf_length,&subjkey->len,PR_TRUE, NULL); | |
225 if (subjkey->data == NULL) return SECFailure; | |
226 buf_length -= (subjkey->data-buf) + subjkey->len; | |
227 buf = subjkey->data + subjkey->len; | |
228 | |
229 extensions->data = NULL; | |
230 extensions->len = 0; | |
231 while (buf_length > 0) { | |
232 /* EXTENSIONS */ | |
233 if (buf[0] == 0xa3) { | |
234 extensions->data = nsslowcert_dataStart(buf,buf_length, | |
235 &extensions->len, PR_FALSE, NULL); | |
236 /* if the DER is bad, we should fail. Previously we accepted | |
237 * bad DER here and treated the extension as missin */ | |
238 if (extensions->data == NULL || | |
239 (extensions->data - buf) + extensions->len != buf_length) | |
240 return SECFailure; | |
241 buf = extensions->data; | |
242 buf_length = extensions->len; | |
243 /* now parse the SEQUENCE holding the extensions. */ | |
244 dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL); | |
245 if (dummy == NULL || | |
246 (dummy - buf) + dummylen != buf_length) | |
247 return SECFailure; | |
248 buf_length -= (dummy - buf); | |
249 buf = dummy; | |
250 /* Now parse the extensions inside this sequence */ | |
251 } | |
252 dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL); | |
253 if (dummy == NULL) return SECFailure; | |
254 buf_length -= (dummy - buf) + dummylen; | |
255 buf = dummy + dummylen; | |
256 } | |
257 return SECSuccess; | |
258 } | |
259 | |
260 static SECStatus | |
261 nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter) | |
262 { | |
263 int rv; | |
264 NSSLOWCERTValidity validity; | |
265 | |
266 rv = nsslowcert_GetValidityFields(c->validity.data,c->validity.len, | |
267 &validity.notBefore,&validity.notAfter); | |
268 if (rv != SECSuccess) { | |
269 return rv; | |
270 } | |
271 | |
272 /* convert DER not-before time */ | |
273 rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore); | |
274 if (rv) { | |
275 return(SECFailure); | |
276 } | |
277 | |
278 /* convert DER not-after time */ | |
279 rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter); | |
280 if (rv) { | |
281 return(SECFailure); | |
282 } | |
283 | |
284 return(SECSuccess); | |
285 } | |
286 | |
287 /* | |
288 * is certa newer than certb? If one is expired, pick the other one. | |
289 */ | |
290 PRBool | |
291 nsslowcert_IsNewer(NSSLOWCERTCertificate *certa, NSSLOWCERTCertificate *certb) | |
292 { | |
293 PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now; | |
294 SECStatus rv; | |
295 PRBool newerbefore, newerafter; | |
296 | |
297 rv = nsslowcert_GetCertTimes(certa, ¬BeforeA, ¬AfterA); | |
298 if ( rv != SECSuccess ) { | |
299 return(PR_FALSE); | |
300 } | |
301 | |
302 rv = nsslowcert_GetCertTimes(certb, ¬BeforeB, ¬AfterB); | |
303 if ( rv != SECSuccess ) { | |
304 return(PR_TRUE); | |
305 } | |
306 | |
307 newerbefore = PR_FALSE; | |
308 if ( LL_CMP(notBeforeA, >, notBeforeB) ) { | |
309 newerbefore = PR_TRUE; | |
310 } | |
311 | |
312 newerafter = PR_FALSE; | |
313 if ( LL_CMP(notAfterA, >, notAfterB) ) { | |
314 newerafter = PR_TRUE; | |
315 } | |
316 | |
317 if ( newerbefore && newerafter ) { | |
318 return(PR_TRUE); | |
319 } | |
320 | |
321 if ( ( !newerbefore ) && ( !newerafter ) ) { | |
322 return(PR_FALSE); | |
323 } | |
324 | |
325 /* get current time */ | |
326 now = PR_Now(); | |
327 | |
328 if ( newerbefore ) { | |
329 /* cert A was issued after cert B, but expires sooner */ | |
330 /* if A is expired, then pick B */ | |
331 if ( LL_CMP(notAfterA, <, now ) ) { | |
332 return(PR_FALSE); | |
333 } | |
334 return(PR_TRUE); | |
335 } else { | |
336 /* cert B was issued after cert A, but expires sooner */ | |
337 /* if B is expired, then pick A */ | |
338 if ( LL_CMP(notAfterB, <, now ) ) { | |
339 return(PR_TRUE); | |
340 } | |
341 return(PR_FALSE); | |
342 } | |
343 } | |
344 | |
345 #define SOFT_DEFAULT_CHUNKSIZE 2048 | |
346 | |
347 static SECStatus | |
348 nsslowcert_KeyFromIssuerAndSN(PLArenaPool *arena, | |
349 SECItem *issuer, SECItem *sn, SECItem *key) | |
350 { | |
351 unsigned int len = sn->len + issuer->len; | |
352 | |
353 if (!arena) { | |
354 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
355 goto loser; | |
356 } | |
357 if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) { | |
358 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
359 goto loser; | |
360 } | |
361 key->data = (unsigned char*)PORT_ArenaAlloc(arena, len); | |
362 if ( !key->data ) { | |
363 goto loser; | |
364 } | |
365 | |
366 key->len = len; | |
367 /* copy the serialNumber */ | |
368 PORT_Memcpy(key->data, sn->data, sn->len); | |
369 | |
370 /* copy the issuer */ | |
371 PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len); | |
372 | |
373 return(SECSuccess); | |
374 | |
375 loser: | |
376 return(SECFailure); | |
377 } | |
378 | |
379 static SECStatus | |
380 nsslowcert_KeyFromIssuerAndSNStatic(unsigned char *space, | |
381 int spaceLen, SECItem *issuer, SECItem *sn, SECItem *key) | |
382 { | |
383 unsigned int len = sn->len + issuer->len; | |
384 | |
385 key->data = pkcs11_allocStaticData(len, space, spaceLen); | |
386 if ( !key->data ) { | |
387 goto loser; | |
388 } | |
389 | |
390 key->len = len; | |
391 /* copy the serialNumber */ | |
392 PORT_Memcpy(key->data, sn->data, sn->len); | |
393 | |
394 /* copy the issuer */ | |
395 PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len); | |
396 | |
397 return(SECSuccess); | |
398 | |
399 loser: | |
400 return(SECFailure); | |
401 } | |
402 | |
403 | |
404 static char * | |
405 nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len) | |
406 { | |
407 unsigned char *buf; | |
408 unsigned int buf_length; | |
409 | |
410 /* unwrap outer sequence */ | |
411 buf=nsslowcert_dataStart(derDN->data,derDN->len,&buf_length,PR_FALSE,NULL); | |
412 if (buf == NULL) return NULL; | |
413 | |
414 /* Walk each RDN */ | |
415 while (buf_length > 0) { | |
416 unsigned char *rdn; | |
417 unsigned int rdn_length; | |
418 | |
419 /* grab next rdn */ | |
420 rdn=nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL); | |
421 if (rdn == NULL) { return NULL; } | |
422 buf_length -= (rdn - buf) + rdn_length; | |
423 buf = rdn+rdn_length; | |
424 | |
425 while (rdn_length > 0) { | |
426 unsigned char *ava; | |
427 unsigned int ava_length; | |
428 unsigned char *oid; | |
429 unsigned int oid_length; | |
430 unsigned char *name; | |
431 unsigned int name_length; | |
432 SECItem oidItem; | |
433 SECOidTag type; | |
434 | |
435 /* unwrap the ava */ | |
436 ava=nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE, | |
437 NULL); | |
438 if (ava == NULL) return NULL; | |
439 rdn_length -= (ava-rdn)+ava_length; | |
440 rdn = ava + ava_length; | |
441 | |
442 oid=nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE, | |
443 NULL); | |
444 if (oid == NULL) { return NULL; } | |
445 ava_length -= (oid-ava)+oid_length; | |
446 ava = oid+oid_length; | |
447 | |
448 name=nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE, | |
449 NULL); | |
450 if (oid == NULL) { return NULL; } | |
451 ava_length -= (name-ava)+name_length; | |
452 ava = name+name_length; | |
453 | |
454 oidItem.data = oid; | |
455 oidItem.len = oid_length; | |
456 type = SECOID_FindOIDTag(&oidItem); | |
457 if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) || | |
458 (type == SEC_OID_RFC1274_MAIL)) { | |
459 /* Email is supposed to be IA5String, so no | |
460 * translation necessary */ | |
461 char *emailAddr; | |
462 emailAddr = (char *)pkcs11_copyStaticData(name,name_length+1, | |
463 (unsigned char *)space,len); | |
464 if (emailAddr) { | |
465 emailAddr[name_length] = 0; | |
466 } | |
467 return emailAddr; | |
468 } | |
469 } | |
470 } | |
471 return NULL; | |
472 } | |
473 | |
474 static char * | |
475 nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space, | |
476 unsigned int len) | |
477 { | |
478 unsigned char *exts; | |
479 unsigned int exts_length; | |
480 | |
481 /* unwrap the sequence */ | |
482 exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len, | |
483 &exts_length, PR_FALSE, NULL); | |
484 /* loop through extension */ | |
485 while (exts && exts_length > 0) { | |
486 unsigned char * ext; | |
487 unsigned int ext_length; | |
488 unsigned char *oid; | |
489 unsigned int oid_length; | |
490 unsigned char *nameList; | |
491 unsigned int nameList_length; | |
492 SECItem oidItem; | |
493 SECOidTag type; | |
494 | |
495 ext = nsslowcert_dataStart(exts, exts_length, &ext_length, | |
496 PR_FALSE, NULL); | |
497 if (ext == NULL) { break; } | |
498 exts_length -= (ext - exts) + ext_length; | |
499 exts = ext+ext_length; | |
500 | |
501 oid=nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL); | |
502 if (oid == NULL) { break; } | |
503 ext_length -= (oid - ext) + oid_length; | |
504 ext = oid+oid_length; | |
505 oidItem.data = oid; | |
506 oidItem.len = oid_length; | |
507 type = SECOID_FindOIDTag(&oidItem); | |
508 | |
509 /* get Alt Extension */ | |
510 if (type != SEC_OID_X509_SUBJECT_ALT_NAME) { | |
511 continue; | |
512 } | |
513 | |
514 /* skip passed the critical flag */ | |
515 if (ext[0] == 0x01) { /* BOOLEAN */ | |
516 unsigned char *dummy; | |
517 unsigned int dummy_length; | |
518 dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length, | |
519 PR_FALSE, NULL); | |
520 if (dummy == NULL) { break; } | |
521 ext_length -= (dummy - ext) + dummy_length; | |
522 ext = dummy+dummy_length; | |
523 } | |
524 | |
525 | |
526 /* unwrap the name list */ | |
527 nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length, | |
528 PR_FALSE, NULL); | |
529 if (nameList == NULL) { break; } | |
530 ext_length -= (nameList - ext) + nameList_length; | |
531 ext = nameList+nameList_length; | |
532 nameList = nsslowcert_dataStart(nameList, nameList_length, | |
533 &nameList_length, PR_FALSE, NULL); | |
534 /* loop through the name list */ | |
535 while (nameList && nameList_length > 0) { | |
536 unsigned char *thisName; | |
537 unsigned int thisName_length; | |
538 | |
539 thisName = nsslowcert_dataStart(nameList, nameList_length, | |
540 &thisName_length, PR_FALSE, NULL); | |
541 if (thisName == NULL) { break; } | |
542 if (nameList[0] == 0xa2) { /* DNS Name */ | |
543 SECItem dn; | |
544 char *emailAddr; | |
545 | |
546 dn.data = thisName; | |
547 dn.len = thisName_length; | |
548 emailAddr = nsslowcert_EmailName(&dn, space, len); | |
549 if (emailAddr) { | |
550 return emailAddr; | |
551 } | |
552 } | |
553 if (nameList[0] == 0x81) { /* RFC 822name */ | |
554 char *emailAddr; | |
555 emailAddr = (char *)pkcs11_copyStaticData(thisName, | |
556 thisName_length+1, (unsigned char *)space,len); | |
557 if (emailAddr) { | |
558 emailAddr[thisName_length] = 0; | |
559 } | |
560 return emailAddr; | |
561 } | |
562 nameList_length -= (thisName-nameList) + thisName_length; | |
563 nameList = thisName + thisName_length; | |
564 } | |
565 break; | |
566 } | |
567 return NULL; | |
568 } | |
569 | |
570 static char * | |
571 nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert) | |
572 { | |
573 char *emailAddr = NULL; | |
574 char *str; | |
575 | |
576 emailAddr = nsslowcert_EmailName(&cert->derSubject,cert->emailAddrSpace, | |
577 sizeof(cert->emailAddrSpace)); | |
578 /* couldn't find the email address in the DN, check the subject Alt name */ | |
579 if (!emailAddr && cert->extensions.data) { | |
580 emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace, | |
581 sizeof(cert->emailAddrSpace)); | |
582 } | |
583 | |
584 | |
585 /* make it lower case */ | |
586 str = emailAddr; | |
587 while ( str && *str ) { | |
588 *str = tolower( *str ); | |
589 str++; | |
590 } | |
591 return emailAddr; | |
592 | |
593 } | |
594 | |
595 /* | |
596 * take a DER certificate and decode it into a certificate structure | |
597 */ | |
598 NSSLOWCERTCertificate * | |
599 nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) | |
600 { | |
601 NSSLOWCERTCertificate *cert; | |
602 int rv; | |
603 | |
604 /* allocate the certificate structure */ | |
605 cert = nsslowcert_CreateCert(); | |
606 | |
607 if ( !cert ) { | |
608 goto loser; | |
609 } | |
610 | |
611 /* point to passed in DER data */ | |
612 cert->derCert = *derSignedCert; | |
613 cert->nickname = NULL; | |
614 cert->certKey.data = NULL; | |
615 cert->referenceCount = 1; | |
616 | |
617 /* decode the certificate info */ | |
618 rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len, | |
619 &cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject, | |
620 &cert->validity, &cert->derSubjKeyInfo, &cert->extensions); | |
621 | |
622 if (rv != SECSuccess) { | |
623 goto loser; | |
624 } | |
625 | |
626 /* cert->subjectKeyID; x509v3 subject key identifier */ | |
627 cert->subjectKeyID.data = NULL; | |
628 cert->subjectKeyID.len = 0; | |
629 cert->dbEntry = NULL; | |
630 cert ->trust = NULL; | |
631 cert ->dbhandle = NULL; | |
632 | |
633 /* generate and save the database key for the cert */ | |
634 rv = nsslowcert_KeyFromIssuerAndSNStatic(cert->certKeySpace, | |
635 sizeof(cert->certKeySpace), &cert->derIssuer, | |
636 &cert->serialNumber, &cert->certKey); | |
637 if ( rv ) { | |
638 goto loser; | |
639 } | |
640 | |
641 /* set the nickname */ | |
642 if ( nickname == NULL ) { | |
643 cert->nickname = NULL; | |
644 } else { | |
645 /* copy and install the nickname */ | |
646 cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace, | |
647 sizeof(cert->nicknameSpace)); | |
648 } | |
649 | |
650 #ifdef FIXME | |
651 /* initialize the subjectKeyID */ | |
652 rv = cert_GetKeyID(cert); | |
653 if ( rv != SECSuccess ) { | |
654 goto loser; | |
655 } | |
656 #endif | |
657 | |
658 /* set the email address */ | |
659 cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert); | |
660 | |
661 | |
662 cert->referenceCount = 1; | |
663 | |
664 return(cert); | |
665 | |
666 loser: | |
667 if (cert) { | |
668 nsslowcert_DestroyCertificate(cert); | |
669 } | |
670 | |
671 return(0); | |
672 } | |
673 | |
674 char * | |
675 nsslowcert_FixupEmailAddr(char *emailAddr) | |
676 { | |
677 char *retaddr; | |
678 char *str; | |
679 | |
680 if ( emailAddr == NULL ) { | |
681 return(NULL); | |
682 } | |
683 | |
684 /* copy the string */ | |
685 str = retaddr = PORT_Strdup(emailAddr); | |
686 if ( str == NULL ) { | |
687 return(NULL); | |
688 } | |
689 | |
690 /* make it lower case */ | |
691 while ( *str ) { | |
692 *str = tolower( *str ); | |
693 str++; | |
694 } | |
695 | |
696 return(retaddr); | |
697 } | |
698 | |
699 | |
700 /* | |
701 * Generate a database key, based on serial number and issuer, from a | |
702 * DER certificate. | |
703 */ | |
704 SECStatus | |
705 nsslowcert_KeyFromDERCert(PLArenaPool *arena, SECItem *derCert, SECItem *key) | |
706 { | |
707 int rv; | |
708 NSSLOWCERTCertKey certkey; | |
709 | |
710 PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey)); | |
711 | |
712 rv = nsslowcert_GetCertFields(derCert->data, derCert->len, | |
713 &certkey.derIssuer, &certkey.serialNumber, NULL, NULL, | |
714 NULL, NULL, NULL); | |
715 | |
716 if ( rv ) { | |
717 goto loser; | |
718 } | |
719 | |
720 return(nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer, | |
721 &certkey.serialNumber, key)); | |
722 loser: | |
723 return(SECFailure); | |
724 } | |
725 | |
726 NSSLOWKEYPublicKey * | |
727 nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert) | |
728 { | |
729 NSSLOWCERTSubjectPublicKeyInfo spki; | |
730 NSSLOWKEYPublicKey *pubk; | |
731 SECItem os; | |
732 SECStatus rv; | |
733 PLArenaPool *arena; | |
734 SECOidTag tag; | |
735 SECItem newDerSubjKeyInfo; | |
736 | |
737 arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); | |
738 if (arena == NULL) | |
739 return NULL; | |
740 | |
741 pubk = (NSSLOWKEYPublicKey *) | |
742 PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey)); | |
743 if (pubk == NULL) { | |
744 PORT_FreeArena (arena, PR_FALSE); | |
745 return NULL; | |
746 } | |
747 | |
748 pubk->arena = arena; | |
749 PORT_Memset(&spki,0,sizeof(spki)); | |
750 | |
751 /* copy the DER into the arena, since Quick DER returns data that points | |
752 into the DER input, which may get freed by the caller */ | |
753 rv = SECITEM_CopyItem(arena, &newDerSubjKeyInfo, &cert->derSubjKeyInfo); | |
754 if ( rv != SECSuccess ) { | |
755 PORT_FreeArena (arena, PR_FALSE); | |
756 return NULL; | |
757 } | |
758 | |
759 /* we haven't bothered decoding the spki struct yet, do it now */ | |
760 rv = SEC_QuickDERDecodeItem(arena, &spki, | |
761 nsslowcert_SubjectPublicKeyInfoTemplate, &newDerSubjKeyInfo); | |
762 if (rv != SECSuccess) { | |
763 PORT_FreeArena (arena, PR_FALSE); | |
764 return NULL; | |
765 } | |
766 | |
767 /* Convert bit string length from bits to bytes */ | |
768 os = spki.subjectPublicKey; | |
769 DER_ConvertBitString (&os); | |
770 | |
771 tag = SECOID_GetAlgorithmTag(&spki.algorithm); | |
772 switch ( tag ) { | |
773 case SEC_OID_X500_RSA_ENCRYPTION: | |
774 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
775 pubk->keyType = NSSLOWKEYRSAKey; | |
776 prepare_low_rsa_pub_key_for_asn1(pubk); | |
777 rv = SEC_QuickDERDecodeItem(arena, pubk, | |
778 nsslowcert_RSAPublicKeyTemplate, &os); | |
779 if (rv == SECSuccess) | |
780 return pubk; | |
781 break; | |
782 case SEC_OID_ANSIX9_DSA_SIGNATURE: | |
783 pubk->keyType = NSSLOWKEYDSAKey; | |
784 prepare_low_dsa_pub_key_for_asn1(pubk); | |
785 rv = SEC_QuickDERDecodeItem(arena, pubk, | |
786 nsslowcert_DSAPublicKeyTemplate, &os); | |
787 if (rv == SECSuccess) return pubk; | |
788 break; | |
789 case SEC_OID_X942_DIFFIE_HELMAN_KEY: | |
790 pubk->keyType = NSSLOWKEYDHKey; | |
791 prepare_low_dh_pub_key_for_asn1(pubk); | |
792 rv = SEC_QuickDERDecodeItem(arena, pubk, | |
793 nsslowcert_DHPublicKeyTemplate, &os); | |
794 if (rv == SECSuccess) return pubk; | |
795 break; | |
796 #ifndef NSS_DISABLE_ECC | |
797 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: | |
798 pubk->keyType = NSSLOWKEYECKey; | |
799 /* Since PKCS#11 directly takes the DER encoding of EC params | |
800 * and public value, we don't need any decoding here. | |
801 */ | |
802 rv = SECITEM_CopyItem(arena, &pubk->u.ec.ecParams.DEREncoding, | |
803 &spki.algorithm.parameters); | |
804 if ( rv != SECSuccess ) | |
805 break; | |
806 | |
807 /* Fill out the rest of the ecParams structure | |
808 * based on the encoded params | |
809 */ | |
810 if (LGEC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding, | |
811 &pubk->u.ec.ecParams) != SECSuccess) | |
812 break; | |
813 | |
814 rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &os); | |
815 if (rv == SECSuccess) return pubk; | |
816 break; | |
817 #endif /* NSS_DISABLE_ECC */ | |
818 default: | |
819 rv = SECFailure; | |
820 break; | |
821 } | |
822 | |
823 lg_nsslowkey_DestroyPublicKey (pubk); | |
824 return NULL; | |
825 } | |
826 |