2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "License"); you may not use this file
4
* except in compliance with the License. You may obtain a copy of
5
* the License at http://www.mozilla.org/MPL/
7
* Software distributed under the License is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the License for the specific language governing
10
* rights and limitations under the License.
12
* The Original Code is the Netscape security libraries.
14
* The Initial Developer of the Original Code is Netscape
15
* Communications Corporation. Portions created by Netscape are
16
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
19
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
20
* Sun Microsystems, Inc. All Rights Reserved.
23
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
25
* Alternatively, the contents of this file may be used under the
26
* terms of the GNU General Public License Version 2 or later (the
27
* "GPL"), in which case the provisions of the GPL are applicable
28
* instead of those above. If you wish to allow use of your
29
* version of this file only under the terms of the GPL and not to
30
* allow others to use your version of this file under the MPL,
31
* indicate your decision by deleting the provisions above and
32
* replace them with the notice and other provisions required by
33
* the GPL. If you do not delete the provisions above, a recipient
34
* may use your version of this file under either the MPL or the
39
* Certificate handling code
41
* $Id: lowcert.c,v 1.17 2004/01/07 23:07:24 jpierre%netscape.com Exp $
55
extern SECStatus EC_FillParams(PRArenaPool *arena,
56
const SECItem *encodedParams,
60
static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = {
61
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) },
62
{ SEC_ASN1_INLINE, offsetof(NSSLOWCERTSubjectPublicKeyInfo,algorithm),
63
SECOID_AlgorithmIDTemplate },
64
{ SEC_ASN1_BIT_STRING,
65
offsetof(NSSLOWCERTSubjectPublicKeyInfo,subjectPublicKey), },
69
static const SEC_ASN1Template nsslowcert_RSAPublicKeyTemplate[] = {
70
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) },
71
{ SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.modulus), },
72
{ SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.publicExponent), },
75
static const SEC_ASN1Template nsslowcert_DSAPublicKeyTemplate[] = {
76
{ SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dsa.publicValue), },
79
static const SEC_ASN1Template nsslowcert_DHPublicKeyTemplate[] = {
80
{ SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dh.publicValue), },
85
* See bugzilla bug 125359
86
* Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
87
* all of the templates above that en/decode into integers must be converted
88
* from ASN.1's signed integer type. This is done by marking either the
89
* source or destination (encoding or decoding, respectively) type as
94
prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
96
pubk->u.rsa.modulus.type = siUnsignedInteger;
97
pubk->u.rsa.publicExponent.type = siUnsignedInteger;
101
prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
103
pubk->u.dsa.publicValue.type = siUnsignedInteger;
104
pubk->u.dsa.params.prime.type = siUnsignedInteger;
105
pubk->u.dsa.params.subPrime.type = siUnsignedInteger;
106
pubk->u.dsa.params.base.type = siUnsignedInteger;
110
prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
112
pubk->u.dh.prime.type = siUnsignedInteger;
113
pubk->u.dh.base.type = siUnsignedInteger;
114
pubk->u.dh.publicValue.type = siUnsignedInteger;
118
* Allow use of default cert database, so that apps(such as mozilla) don't
119
* have to pass the handle all over the place.
121
static NSSLOWCERTCertDBHandle *default_pcert_db_handle = 0;
124
nsslowcert_SetDefaultCertDB(NSSLOWCERTCertDBHandle *handle)
126
default_pcert_db_handle = handle;
131
NSSLOWCERTCertDBHandle *
132
nsslowcert_GetDefaultCertDB(void)
134
return(default_pcert_db_handle);
138
* simple cert decoder to avoid the cost of asn1 engine
140
static unsigned char *
141
nsslowcert_dataStart(unsigned char *buf, unsigned int length,
142
unsigned int *data_length, PRBool includeTag,
143
unsigned char* rettag) {
145
unsigned int used_length= 0;
147
tag = buf[used_length++];
153
/* blow out when we come to the end */
158
*data_length = buf[used_length++];
160
if (*data_length&0x80) {
161
int len_count = *data_length & 0x7f;
165
while (len_count-- > 0) {
166
*data_length = (*data_length << 8) | buf[used_length++];
170
if (*data_length > (length-used_length) ) {
171
*data_length = length-used_length;
174
if (includeTag) *data_length += used_length;
176
return (buf + (includeTag ? 0 : used_length));
179
static void SetTimeType(SECItem* item, unsigned char tagtype)
182
case SEC_ASN1_UTC_TIME:
183
item->type = siUTCTime;
186
case SEC_ASN1_GENERALIZED_TIME:
187
item->type = siGeneralizedTime;
197
nsslowcert_GetValidityFields(unsigned char *buf,int buf_length,
198
SECItem *notBefore, SECItem *notAfter)
200
unsigned char tagtype;
201
notBefore->data = nsslowcert_dataStart(buf,buf_length,
202
¬Before->len,PR_FALSE, &tagtype);
203
if (notBefore->data == NULL) return SECFailure;
204
SetTimeType(notBefore, tagtype);
205
buf_length -= (notBefore->data-buf) + notBefore->len;
206
buf = notBefore->data + notBefore->len;
207
notAfter->data = nsslowcert_dataStart(buf,buf_length,
208
¬After->len,PR_FALSE, &tagtype);
209
if (notAfter->data == NULL) return SECFailure;
210
SetTimeType(notAfter, tagtype);
215
nsslowcert_GetCertFields(unsigned char *cert,int cert_length,
216
SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject,
217
SECItem *valid, SECItem *subjkey)
220
unsigned int buf_length;
221
unsigned char *dummy;
222
unsigned int dummylen;
224
/* get past the signature wrap */
225
buf = nsslowcert_dataStart(cert,cert_length,&buf_length,PR_FALSE, NULL);
226
if (buf == NULL) return SECFailure;
227
/* get into the raw cert data */
228
buf = nsslowcert_dataStart(buf,buf_length,&buf_length,PR_FALSE, NULL);
229
if (buf == NULL) return SECFailure;
230
/* skip past any optional version number */
231
if ((buf[0] & 0xa0) == 0xa0) {
232
dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL);
233
if (dummy == NULL) return SECFailure;
234
buf_length -= (dummy-buf) + dummylen;
235
buf = dummy + dummylen;
239
derSN->data=nsslowcert_dataStart(buf,buf_length,&derSN->len,PR_TRUE, NULL);
241
serial->data = nsslowcert_dataStart(buf,buf_length,&serial->len,PR_FALSE, NULL);
242
if (serial->data == NULL) return SECFailure;
243
buf_length -= (serial->data-buf) + serial->len;
244
buf = serial->data + serial->len;
246
dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL);
247
if (dummy == NULL) return SECFailure;
248
buf_length -= (dummy-buf) + dummylen;
249
buf = dummy + dummylen;
251
issuer->data = nsslowcert_dataStart(buf,buf_length,&issuer->len,PR_TRUE, NULL);
252
if (issuer->data == NULL) return SECFailure;
253
buf_length -= (issuer->data-buf) + issuer->len;
254
buf = issuer->data + issuer->len;
256
/* only wanted issuer/SN */
261
valid->data = nsslowcert_dataStart(buf,buf_length,&valid->len,PR_FALSE, NULL);
262
if (valid->data == NULL) return SECFailure;
263
buf_length -= (valid->data-buf) + valid->len;
264
buf = valid->data + valid->len;
266
subject->data=nsslowcert_dataStart(buf,buf_length,&subject->len,PR_TRUE, NULL);
267
if (subject->data == NULL) return SECFailure;
268
buf_length -= (subject->data-buf) + subject->len;
269
buf = subject->data + subject->len;
270
/* subject key info */
271
subjkey->data=nsslowcert_dataStart(buf,buf_length,&subjkey->len,PR_TRUE, NULL);
272
if (subjkey->data == NULL) return SECFailure;
273
buf_length -= (subjkey->data-buf) + subjkey->len;
274
buf = subjkey->data + subjkey->len;
279
nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
282
NSSLOWCERTValidity validity;
284
rv = nsslowcert_GetValidityFields(c->validity.data,c->validity.len,
285
&validity.notBefore,&validity.notAfter);
286
if (rv != SECSuccess) {
290
/* convert DER not-before time */
291
rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore);
296
/* convert DER not-after time */
297
rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter);
306
* is certa newer than certb? If one is expired, pick the other one.
309
nsslowcert_IsNewer(NSSLOWCERTCertificate *certa, NSSLOWCERTCertificate *certb)
311
PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
313
PRBool newerbefore, newerafter;
315
rv = nsslowcert_GetCertTimes(certa, ¬BeforeA, ¬AfterA);
316
if ( rv != SECSuccess ) {
320
rv = nsslowcert_GetCertTimes(certb, ¬BeforeB, ¬AfterB);
321
if ( rv != SECSuccess ) {
325
newerbefore = PR_FALSE;
326
if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
327
newerbefore = PR_TRUE;
330
newerafter = PR_FALSE;
331
if ( LL_CMP(notAfterA, >, notAfterB) ) {
332
newerafter = PR_TRUE;
335
if ( newerbefore && newerafter ) {
339
if ( ( !newerbefore ) && ( !newerafter ) ) {
343
/* get current time */
347
/* cert A was issued after cert B, but expires sooner */
348
/* if A is expired, then pick B */
349
if ( LL_CMP(notAfterA, <, now ) ) {
354
/* cert B was issued after cert A, but expires sooner */
355
/* if B is expired, then pick A */
356
if ( LL_CMP(notAfterB, <, now ) ) {
363
#define SOFT_DEFAULT_CHUNKSIZE 2048
367
nsslowcert_KeyFromIssuerAndSN(PRArenaPool *arena, SECItem *issuer, SECItem *sn,
370
unsigned int len = sn->len + issuer->len;
374
key->data = (unsigned char*)PORT_ArenaAlloc(arena, len);
376
if (len > key->len) {
377
key->data = (unsigned char*)PORT_ArenaAlloc(arena, len);
385
/* copy the serialNumber */
386
PORT_Memcpy(key->data, sn->data, sn->len);
388
/* copy the issuer */
389
PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
400
* take a DER certificate and decode it into a certificate structure
402
NSSLOWCERTCertificate *
403
nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname)
405
NSSLOWCERTCertificate *cert;
408
/* allocate the certificate structure */
409
cert = nsslowcert_CreateCert();
415
/* point to passed in DER data */
416
cert->derCert = *derSignedCert;
417
cert->nickname = NULL;
418
cert->certKey.data = NULL;
419
cert->referenceCount = 1;
421
/* decode the certificate info */
422
rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len,
423
&cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject,
424
&cert->validity, &cert->derSubjKeyInfo);
426
/* cert->subjectKeyID; x509v3 subject key identifier */
427
cert->subjectKeyID.data = NULL;
428
cert->subjectKeyID.len = 0;
429
cert->dbEntry = NULL;
432
/* generate and save the database key for the cert */
433
cert->certKey.data = cert->certKeySpace;
434
cert->certKey.len = sizeof(cert->certKeySpace);
435
rv = nsslowcert_KeyFromIssuerAndSN(NULL, &cert->derIssuer,
436
&cert->serialNumber, &cert->certKey);
441
/* set the nickname */
442
if ( nickname == NULL ) {
443
cert->nickname = NULL;
445
/* copy and install the nickname */
446
cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace,
447
sizeof(cert->nicknameSpace));
451
/* initialize the subjectKeyID */
452
rv = cert_GetKeyID(cert);
453
if ( rv != SECSuccess ) {
457
/* set the email address */
458
cert->emailAddr = CERT_GetCertificateEmailAddress(cert);
462
cert->referenceCount = 1;
468
nsslowcert_DestroyCertificate(cert);
475
nsslowcert_FixupEmailAddr(char *emailAddr)
480
if ( emailAddr == NULL ) {
484
/* copy the string */
485
str = retaddr = PORT_Strdup(emailAddr);
490
/* make it lower case */
492
*str = tolower( *str );
501
* Generate a database key, based on serial number and issuer, from a
505
nsslowcert_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key)
508
NSSLOWCERTCertKey certkey;
510
PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey));
512
rv = nsslowcert_GetCertFields(derCert->data, derCert->len,
513
&certkey.derIssuer, &certkey.serialNumber, NULL, NULL, NULL, NULL);
519
return(nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
520
&certkey.serialNumber, key));
526
nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert)
528
NSSLOWCERTSubjectPublicKeyInfo spki;
529
NSSLOWKEYPublicKey *pubk;
534
SECItem newDerSubjKeyInfo;
536
arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
540
pubk = (NSSLOWKEYPublicKey *)
541
PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey));
543
PORT_FreeArena (arena, PR_FALSE);
548
PORT_Memset(&spki,0,sizeof(spki));
550
/* copy the DER into the arena, since Quick DER returns data that points
551
into the DER input, which may get freed by the caller */
552
rv = SECITEM_CopyItem(arena, &newDerSubjKeyInfo, &cert->derSubjKeyInfo);
553
if ( rv != SECSuccess ) {
554
PORT_FreeArena (arena, PR_FALSE);
558
/* we haven't bothered decoding the spki struct yet, do it now */
559
rv = SEC_QuickDERDecodeItem(arena, &spki,
560
nsslowcert_SubjectPublicKeyInfoTemplate, &newDerSubjKeyInfo);
561
if (rv != SECSuccess) {
562
PORT_FreeArena (arena, PR_FALSE);
566
/* Convert bit string length from bits to bytes */
567
os = spki.subjectPublicKey;
568
DER_ConvertBitString (&os);
570
tag = SECOID_GetAlgorithmTag(&spki.algorithm);
572
case SEC_OID_X500_RSA_ENCRYPTION:
573
case SEC_OID_PKCS1_RSA_ENCRYPTION:
574
pubk->keyType = NSSLOWKEYRSAKey;
575
prepare_low_rsa_pub_key_for_asn1(pubk);
576
rv = SEC_QuickDERDecodeItem(arena, pubk,
577
nsslowcert_RSAPublicKeyTemplate, &os);
578
if (rv == SECSuccess)
581
case SEC_OID_ANSIX9_DSA_SIGNATURE:
582
pubk->keyType = NSSLOWKEYDSAKey;
583
prepare_low_dsa_pub_key_for_asn1(pubk);
584
rv = SEC_QuickDERDecodeItem(arena, pubk,
585
nsslowcert_DSAPublicKeyTemplate, &os);
586
if (rv == SECSuccess) return pubk;
588
case SEC_OID_X942_DIFFIE_HELMAN_KEY:
589
pubk->keyType = NSSLOWKEYDHKey;
590
prepare_low_dh_pub_key_for_asn1(pubk);
591
rv = SEC_QuickDERDecodeItem(arena, pubk,
592
nsslowcert_DHPublicKeyTemplate, &os);
593
if (rv == SECSuccess) return pubk;
595
#ifdef NSS_ENABLE_ECC
596
case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
597
pubk->keyType = NSSLOWKEYECKey;
598
/* Since PKCS#11 directly takes the DER encoding of EC params
599
* and public value, we don't need any decoding here.
601
rv = SECITEM_CopyItem(arena, &pubk->u.ec.ecParams.DEREncoding,
602
&spki.algorithm.parameters);
603
if ( rv != SECSuccess )
606
/* Fill out the rest of the ecParams structure
607
* based on the encoded params
609
if (EC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding,
610
&pubk->u.ec.ecParams) != SECSuccess)
613
rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &os);
614
if (rv == SECSuccess) return pubk;
616
#endif /* NSS_ENABLE_ECC */
622
nsslowkey_DestroyPublicKey (pubk);