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