security/nss/lib/softoken/legacydb/lowcert.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/softoken/legacydb/lowcert.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,826 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * Certificate handling code
    1.10 + */
    1.11 +
    1.12 +#include "seccomon.h"
    1.13 +#include "secder.h"
    1.14 +#include "nssilock.h"
    1.15 +#include "lowkeyi.h"
    1.16 +#include "secasn1.h"
    1.17 +#include "secoid.h"
    1.18 +#include "secerr.h"
    1.19 +#include "pcert.h"
    1.20 +
    1.21 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    1.22 +
    1.23 +static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = {
    1.24 +    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) },
    1.25 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    1.26 +        offsetof(NSSLOWCERTSubjectPublicKeyInfo,algorithm),
    1.27 +        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    1.28 +    { SEC_ASN1_BIT_STRING,
    1.29 +          offsetof(NSSLOWCERTSubjectPublicKeyInfo,subjectPublicKey), },
    1.30 +    { 0, }
    1.31 +};
    1.32 +
    1.33 +static const SEC_ASN1Template nsslowcert_RSAPublicKeyTemplate[] = {
    1.34 +    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) },
    1.35 +    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.modulus), },
    1.36 +    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.publicExponent), },
    1.37 +    { 0, }
    1.38 +};
    1.39 +static const SEC_ASN1Template nsslowcert_DSAPublicKeyTemplate[] = {
    1.40 +    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dsa.publicValue), },
    1.41 +    { 0, }
    1.42 +};
    1.43 +static const SEC_ASN1Template nsslowcert_DHPublicKeyTemplate[] = {
    1.44 +    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dh.publicValue), },
    1.45 +    { 0, }
    1.46 +};
    1.47 +
    1.48 +/*
    1.49 + * See bugzilla bug 125359
    1.50 + * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
    1.51 + * all of the templates above that en/decode into integers must be converted
    1.52 + * from ASN.1's signed integer type.  This is done by marking either the
    1.53 + * source or destination (encoding or decoding, respectively) type as
    1.54 + * siUnsignedInteger.
    1.55 + */
    1.56 +
    1.57 +static void
    1.58 +prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
    1.59 +{
    1.60 +    pubk->u.rsa.modulus.type = siUnsignedInteger;
    1.61 +    pubk->u.rsa.publicExponent.type = siUnsignedInteger;
    1.62 +}
    1.63 +
    1.64 +static void
    1.65 +prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
    1.66 +{
    1.67 +    pubk->u.dsa.publicValue.type = siUnsignedInteger;
    1.68 +    pubk->u.dsa.params.prime.type = siUnsignedInteger;
    1.69 +    pubk->u.dsa.params.subPrime.type = siUnsignedInteger;
    1.70 +    pubk->u.dsa.params.base.type = siUnsignedInteger;
    1.71 +}
    1.72 +
    1.73 +static void
    1.74 +prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
    1.75 +{
    1.76 +    pubk->u.dh.prime.type = siUnsignedInteger;
    1.77 +    pubk->u.dh.base.type = siUnsignedInteger;
    1.78 +    pubk->u.dh.publicValue.type = siUnsignedInteger;
    1.79 +}
    1.80 +
    1.81 +/*
    1.82 + * simple cert decoder to avoid the cost of asn1 engine
    1.83 + */ 
    1.84 +static unsigned char *
    1.85 +nsslowcert_dataStart(unsigned char *buf, unsigned int length, 
    1.86 +			unsigned int *data_length, PRBool includeTag,
    1.87 +                        unsigned char* rettag) {
    1.88 +    unsigned char tag;
    1.89 +    unsigned int used_length= 0;
    1.90 +
    1.91 +    /* need at least a tag and a 1 byte length */
    1.92 +    if (length < 2) {
    1.93 +	return NULL;
    1.94 +    }
    1.95 +
    1.96 +    tag = buf[used_length++];
    1.97 +
    1.98 +    if (rettag) {
    1.99 +        *rettag = tag;
   1.100 +    }
   1.101 +
   1.102 +    /* blow out when we come to the end */
   1.103 +    if (tag == 0) {
   1.104 +	return NULL;
   1.105 +    }
   1.106 +
   1.107 +    *data_length = buf[used_length++];
   1.108 +
   1.109 +    if (*data_length&0x80) {
   1.110 +	int  len_count = *data_length & 0x7f;
   1.111 +
   1.112 +	if (len_count+used_length > length) {
   1.113 +	   return NULL;
   1.114 +	}
   1.115 +
   1.116 +	*data_length = 0;
   1.117 +
   1.118 +	while (len_count-- > 0) {
   1.119 +	    *data_length = (*data_length << 8) | buf[used_length++];
   1.120 +	} 
   1.121 +    }
   1.122 +
   1.123 +    if (*data_length > (length-used_length) ) {
   1.124 +	*data_length = length-used_length;
   1.125 +	return NULL;
   1.126 +    }
   1.127 +    if (includeTag) *data_length += used_length;
   1.128 +
   1.129 +    return (buf + (includeTag ? 0 : used_length));	
   1.130 +}
   1.131 +
   1.132 +static void SetTimeType(SECItem* item, unsigned char tagtype)
   1.133 +{
   1.134 +    switch (tagtype) {
   1.135 +        case SEC_ASN1_UTC_TIME:
   1.136 +            item->type = siUTCTime;
   1.137 +            break;
   1.138 +
   1.139 +        case SEC_ASN1_GENERALIZED_TIME:
   1.140 +            item->type = siGeneralizedTime;
   1.141 +            break;
   1.142 +
   1.143 +        default:
   1.144 +            PORT_Assert(0);
   1.145 +            break;
   1.146 +    }
   1.147 +}
   1.148 +
   1.149 +static int
   1.150 +nsslowcert_GetValidityFields(unsigned char *buf,int buf_length,
   1.151 +	SECItem *notBefore, SECItem *notAfter)
   1.152 +{
   1.153 +    unsigned char tagtype;
   1.154 +    notBefore->data = nsslowcert_dataStart(buf,buf_length,
   1.155 +						&notBefore->len,PR_FALSE, &tagtype);
   1.156 +    if (notBefore->data == NULL) return SECFailure;
   1.157 +    SetTimeType(notBefore, tagtype);
   1.158 +    buf_length -= (notBefore->data-buf) + notBefore->len;
   1.159 +    buf = notBefore->data + notBefore->len;
   1.160 +    notAfter->data = nsslowcert_dataStart(buf,buf_length,
   1.161 +						&notAfter->len,PR_FALSE, &tagtype);
   1.162 +    if (notAfter->data == NULL) return SECFailure;
   1.163 +    SetTimeType(notAfter, tagtype);
   1.164 +    return SECSuccess;
   1.165 +}
   1.166 +
   1.167 +static int
   1.168 +nsslowcert_GetCertFields(unsigned char *cert,int cert_length,
   1.169 +	SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject,
   1.170 +	SECItem *valid, SECItem *subjkey, SECItem *extensions)
   1.171 +{
   1.172 +    unsigned char *buf;
   1.173 +    unsigned int buf_length;
   1.174 +    unsigned char *dummy;
   1.175 +    unsigned int dummylen;
   1.176 +
   1.177 +    /* get past the signature wrap */
   1.178 +    buf = nsslowcert_dataStart(cert,cert_length,&buf_length,PR_FALSE, NULL);
   1.179 +    if (buf == NULL) return SECFailure;
   1.180 +    /* get into the raw cert data */
   1.181 +    buf = nsslowcert_dataStart(buf,buf_length,&buf_length,PR_FALSE, NULL);
   1.182 +    if (buf == NULL) return SECFailure;
   1.183 +    /* skip past any optional version number */
   1.184 +    if ((buf[0] & 0xa0) == 0xa0) {
   1.185 +	dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL);
   1.186 +	if (dummy == NULL) return SECFailure;
   1.187 +	buf_length -= (dummy-buf) + dummylen;
   1.188 +	buf = dummy + dummylen;
   1.189 +    }
   1.190 +    /* serial number */
   1.191 +    if (derSN) {
   1.192 +	derSN->data=nsslowcert_dataStart(buf,buf_length,&derSN->len,PR_TRUE, NULL);
   1.193 +	/* derSN->data  doesn't need to be checked because if it fails so will
   1.194 +	 * serial->data below. The only difference between the two calls is
   1.195 +	 * whether or not the tags are included in the returned buffer */
   1.196 +    }
   1.197 +    serial->data = nsslowcert_dataStart(buf,buf_length,&serial->len,PR_FALSE, NULL);
   1.198 +    if (serial->data == NULL) return SECFailure;
   1.199 +    buf_length -= (serial->data-buf) + serial->len;
   1.200 +    buf = serial->data + serial->len;
   1.201 +    /* skip the OID */
   1.202 +    dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL);
   1.203 +    if (dummy == NULL) return SECFailure;
   1.204 +    buf_length -= (dummy-buf) + dummylen;
   1.205 +    buf = dummy + dummylen;
   1.206 +    /* issuer */
   1.207 +    issuer->data = nsslowcert_dataStart(buf,buf_length,&issuer->len,PR_TRUE, NULL);
   1.208 +    if (issuer->data == NULL) return SECFailure;
   1.209 +    buf_length -= (issuer->data-buf) + issuer->len;
   1.210 +    buf = issuer->data + issuer->len;
   1.211 +
   1.212 +    /* only wanted issuer/SN */
   1.213 +    if (valid == NULL) {
   1.214 +	return SECSuccess;
   1.215 +    }
   1.216 +    /* validity */
   1.217 +    valid->data = nsslowcert_dataStart(buf,buf_length,&valid->len,PR_FALSE, NULL);
   1.218 +    if (valid->data == NULL) return SECFailure;
   1.219 +    buf_length -= (valid->data-buf) + valid->len;
   1.220 +    buf = valid->data + valid->len;
   1.221 +    /*subject */
   1.222 +    subject->data=nsslowcert_dataStart(buf,buf_length,&subject->len,PR_TRUE, NULL);
   1.223 +    if (subject->data == NULL) return SECFailure;
   1.224 +    buf_length -= (subject->data-buf) + subject->len;
   1.225 +    buf = subject->data + subject->len;
   1.226 +    /* subject  key info */
   1.227 +    subjkey->data=nsslowcert_dataStart(buf,buf_length,&subjkey->len,PR_TRUE, NULL);
   1.228 +    if (subjkey->data == NULL) return SECFailure;
   1.229 +    buf_length -= (subjkey->data-buf) + subjkey->len;
   1.230 +    buf = subjkey->data + subjkey->len;
   1.231 +
   1.232 +    extensions->data = NULL;
   1.233 +    extensions->len = 0;
   1.234 +    while (buf_length > 0) {
   1.235 +	/* EXTENSIONS */
   1.236 +	if (buf[0] == 0xa3) {
   1.237 +	    extensions->data = nsslowcert_dataStart(buf,buf_length, 
   1.238 +					&extensions->len, PR_FALSE, NULL);
   1.239 +	    /* if the DER is bad, we should fail. Previously we accepted
   1.240 +	     * bad DER here and treated the extension as missin */
   1.241 +	    if (extensions->data == NULL ||
   1.242 +	       (extensions->data - buf) + extensions->len != buf_length) 
   1.243 +                return SECFailure;
   1.244 +            buf = extensions->data;
   1.245 +            buf_length = extensions->len; 
   1.246 +            /* now parse the SEQUENCE holding the extensions. */
   1.247 +            dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL);
   1.248 +            if (dummy == NULL ||
   1.249 +               (dummy - buf) + dummylen != buf_length)
   1.250 +                return SECFailure;
   1.251 +            buf_length -= (dummy - buf);
   1.252 +            buf = dummy;
   1.253 +            /* Now parse the extensions inside this sequence */
   1.254 +	}
   1.255 +	dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL);
   1.256 +	if (dummy == NULL) return SECFailure;
   1.257 +	buf_length -= (dummy - buf) + dummylen;
   1.258 +	buf = dummy + dummylen;
   1.259 +    }
   1.260 +    return SECSuccess;
   1.261 +}
   1.262 +
   1.263 +static SECStatus
   1.264 +nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
   1.265 +{
   1.266 +    int rv;
   1.267 +    NSSLOWCERTValidity validity;
   1.268 +
   1.269 +    rv = nsslowcert_GetValidityFields(c->validity.data,c->validity.len,
   1.270 +				&validity.notBefore,&validity.notAfter);
   1.271 +    if (rv != SECSuccess) {
   1.272 +	return rv;
   1.273 +    }
   1.274 +    
   1.275 +    /* convert DER not-before time */
   1.276 +    rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore);
   1.277 +    if (rv) {
   1.278 +        return(SECFailure);
   1.279 +    }
   1.280 +    
   1.281 +    /* convert DER not-after time */
   1.282 +    rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter);
   1.283 +    if (rv) {
   1.284 +        return(SECFailure);
   1.285 +    }
   1.286 +
   1.287 +    return(SECSuccess);
   1.288 +}
   1.289 +
   1.290 +/*
   1.291 + * is certa newer than certb?  If one is expired, pick the other one.
   1.292 + */
   1.293 +PRBool
   1.294 +nsslowcert_IsNewer(NSSLOWCERTCertificate *certa, NSSLOWCERTCertificate *certb)
   1.295 +{
   1.296 +    PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
   1.297 +    SECStatus rv;
   1.298 +    PRBool newerbefore, newerafter;
   1.299 +    
   1.300 +    rv = nsslowcert_GetCertTimes(certa, &notBeforeA, &notAfterA);
   1.301 +    if ( rv != SECSuccess ) {
   1.302 +	return(PR_FALSE);
   1.303 +    }
   1.304 +    
   1.305 +    rv = nsslowcert_GetCertTimes(certb, &notBeforeB, &notAfterB);
   1.306 +    if ( rv != SECSuccess ) {
   1.307 +	return(PR_TRUE);
   1.308 +    }
   1.309 +
   1.310 +    newerbefore = PR_FALSE;
   1.311 +    if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
   1.312 +	newerbefore = PR_TRUE;
   1.313 +    }
   1.314 +
   1.315 +    newerafter = PR_FALSE;
   1.316 +    if ( LL_CMP(notAfterA, >, notAfterB) ) {
   1.317 +	newerafter = PR_TRUE;
   1.318 +    }
   1.319 +    
   1.320 +    if ( newerbefore && newerafter ) {
   1.321 +	return(PR_TRUE);
   1.322 +    }
   1.323 +    
   1.324 +    if ( ( !newerbefore ) && ( !newerafter ) ) {
   1.325 +	return(PR_FALSE);
   1.326 +    }
   1.327 +
   1.328 +    /* get current time */
   1.329 +    now = PR_Now();
   1.330 +
   1.331 +    if ( newerbefore ) {
   1.332 +	/* cert A was issued after cert B, but expires sooner */
   1.333 +	/* if A is expired, then pick B */
   1.334 +	if ( LL_CMP(notAfterA, <, now ) ) {
   1.335 +	    return(PR_FALSE);
   1.336 +	}
   1.337 +	return(PR_TRUE);
   1.338 +    } else {
   1.339 +	/* cert B was issued after cert A, but expires sooner */
   1.340 +	/* if B is expired, then pick A */
   1.341 +	if ( LL_CMP(notAfterB, <, now ) ) {
   1.342 +	    return(PR_TRUE);
   1.343 +	}
   1.344 +	return(PR_FALSE);
   1.345 +    }
   1.346 +}
   1.347 +
   1.348 +#define SOFT_DEFAULT_CHUNKSIZE 2048
   1.349 +
   1.350 +static SECStatus
   1.351 +nsslowcert_KeyFromIssuerAndSN(PLArenaPool *arena,
   1.352 +			      SECItem *issuer, SECItem *sn, SECItem *key)
   1.353 +{
   1.354 +    unsigned int len = sn->len + issuer->len;
   1.355 +
   1.356 +    if (!arena) {
   1.357 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.358 +	goto loser;
   1.359 +    }
   1.360 +    if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) {
   1.361 +	PORT_SetError(SEC_ERROR_INPUT_LEN);
   1.362 +	goto loser;
   1.363 +    }
   1.364 +    key->data = (unsigned char*)PORT_ArenaAlloc(arena, len);
   1.365 +    if ( !key->data ) {
   1.366 +	goto loser;
   1.367 +    }
   1.368 +
   1.369 +    key->len = len;
   1.370 +    /* copy the serialNumber */
   1.371 +    PORT_Memcpy(key->data, sn->data, sn->len);
   1.372 +
   1.373 +    /* copy the issuer */
   1.374 +    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
   1.375 +
   1.376 +    return(SECSuccess);
   1.377 +
   1.378 +loser:
   1.379 +    return(SECFailure);
   1.380 +}
   1.381 +
   1.382 +static SECStatus
   1.383 +nsslowcert_KeyFromIssuerAndSNStatic(unsigned char *space,
   1.384 +	int spaceLen, SECItem *issuer, SECItem *sn, SECItem *key)
   1.385 +{
   1.386 +    unsigned int len = sn->len + issuer->len;
   1.387 +
   1.388 +    key->data = pkcs11_allocStaticData(len, space, spaceLen);
   1.389 +    if ( !key->data ) {
   1.390 +	goto loser;
   1.391 +    }
   1.392 +
   1.393 +    key->len = len;
   1.394 +    /* copy the serialNumber */
   1.395 +    PORT_Memcpy(key->data, sn->data, sn->len);
   1.396 +
   1.397 +    /* copy the issuer */
   1.398 +    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
   1.399 +
   1.400 +    return(SECSuccess);
   1.401 +
   1.402 +loser:
   1.403 +    return(SECFailure);
   1.404 +}
   1.405 +
   1.406 +
   1.407 +static char *
   1.408 +nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len)
   1.409 +{
   1.410 +    unsigned char *buf;
   1.411 +    unsigned int buf_length;
   1.412 +
   1.413 +    /* unwrap outer sequence */
   1.414 +    buf=nsslowcert_dataStart(derDN->data,derDN->len,&buf_length,PR_FALSE,NULL);
   1.415 +    if (buf == NULL) return NULL;
   1.416 +
   1.417 +    /* Walk each RDN */
   1.418 +    while (buf_length > 0) {
   1.419 +	unsigned char *rdn;
   1.420 +	unsigned int rdn_length;
   1.421 +
   1.422 +	/* grab next rdn */
   1.423 +	rdn=nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL);
   1.424 +	if (rdn == NULL) { return NULL; }
   1.425 +	buf_length -= (rdn - buf) + rdn_length;
   1.426 +	buf = rdn+rdn_length;
   1.427 +
   1.428 +	while (rdn_length > 0) {
   1.429 +	    unsigned char *ava;
   1.430 +	    unsigned int ava_length;
   1.431 +	    unsigned char *oid;
   1.432 +	    unsigned int oid_length;
   1.433 +	    unsigned char *name;
   1.434 +	    unsigned int name_length;
   1.435 +	    SECItem oidItem;
   1.436 +	    SECOidTag type;
   1.437 +
   1.438 +	    /* unwrap the ava */
   1.439 +	    ava=nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE, 
   1.440 +					NULL);
   1.441 +	    if (ava == NULL) return NULL;
   1.442 +	    rdn_length -= (ava-rdn)+ava_length;
   1.443 +	    rdn = ava + ava_length;
   1.444 +
   1.445 +	    oid=nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE, 
   1.446 +					NULL);
   1.447 +	    if (oid == NULL) { return NULL; }
   1.448 +	    ava_length -= (oid-ava)+oid_length;
   1.449 +	    ava = oid+oid_length;
   1.450 +
   1.451 +	    name=nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE, 
   1.452 +					NULL);
   1.453 +	    if (oid == NULL) { return NULL; }
   1.454 +	    ava_length -= (name-ava)+name_length;
   1.455 +	    ava = name+name_length;
   1.456 +
   1.457 +	    oidItem.data = oid;
   1.458 +	    oidItem.len = oid_length;
   1.459 +	    type = SECOID_FindOIDTag(&oidItem);
   1.460 +	    if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) || 
   1.461 +					(type == SEC_OID_RFC1274_MAIL)) {
   1.462 +		/* Email is supposed to be IA5String, so no 
   1.463 +		 * translation necessary */
   1.464 +		char *emailAddr;
   1.465 +		emailAddr = (char *)pkcs11_copyStaticData(name,name_length+1,
   1.466 +					(unsigned char *)space,len);
   1.467 +		if (emailAddr) {
   1.468 +		    emailAddr[name_length] = 0;
   1.469 +		}
   1.470 +		return emailAddr;
   1.471 +	    }
   1.472 +	}
   1.473 +    }
   1.474 +    return NULL;
   1.475 +}
   1.476 +
   1.477 +static char *
   1.478 +nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space, 
   1.479 +			unsigned int len)
   1.480 +{
   1.481 +    unsigned char *exts;
   1.482 +    unsigned int exts_length;
   1.483 +
   1.484 +    /* unwrap the sequence */
   1.485 +    exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len,
   1.486 +				 &exts_length, PR_FALSE, NULL);
   1.487 +    /* loop through extension */
   1.488 +    while (exts && exts_length > 0) {
   1.489 +	unsigned char * ext;
   1.490 +	unsigned int ext_length;
   1.491 +	unsigned char *oid;	
   1.492 +	unsigned int oid_length;
   1.493 +	unsigned char *nameList;
   1.494 +	unsigned int nameList_length;
   1.495 +	SECItem oidItem;
   1.496 +	SECOidTag type;
   1.497 +
   1.498 +	ext = nsslowcert_dataStart(exts, exts_length, &ext_length, 
   1.499 +					PR_FALSE, NULL);
   1.500 +	if (ext == NULL) { break; }
   1.501 +	exts_length -= (ext - exts) + ext_length;
   1.502 +	exts = ext+ext_length;
   1.503 +
   1.504 +	oid=nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL);
   1.505 +	if (oid == NULL) { break; }
   1.506 +	ext_length -= (oid - ext) + oid_length;
   1.507 +	ext = oid+oid_length;
   1.508 +	oidItem.data = oid;
   1.509 +	oidItem.len = oid_length;
   1.510 +	type = SECOID_FindOIDTag(&oidItem);
   1.511 +
   1.512 +	/* get Alt Extension */
   1.513 +	if (type != SEC_OID_X509_SUBJECT_ALT_NAME) {
   1.514 +		continue;
   1.515 +	}
   1.516 +
   1.517 +	/* skip passed the critical flag */
   1.518 +	if (ext[0] == 0x01) { /* BOOLEAN */
   1.519 +	    unsigned char *dummy;
   1.520 +	    unsigned int dummy_length;
   1.521 +	    dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length, 
   1.522 +					PR_FALSE, NULL);
   1.523 +	    if (dummy == NULL) { break; } 
   1.524 +	    ext_length -= (dummy - ext) + dummy_length;
   1.525 +	    ext = dummy+dummy_length;
   1.526 +	}
   1.527 +
   1.528 +	   
   1.529 +	/* unwrap the name list */ 
   1.530 +	nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length, 
   1.531 +					PR_FALSE, NULL);
   1.532 +	if (nameList == NULL) { break; }
   1.533 +	ext_length -= (nameList - ext) + nameList_length;
   1.534 +	ext = nameList+nameList_length;
   1.535 +	nameList = nsslowcert_dataStart(nameList, nameList_length,
   1.536 +					&nameList_length, PR_FALSE, NULL);
   1.537 +	/* loop through the name list */
   1.538 +	while (nameList && nameList_length > 0) {
   1.539 +	    unsigned char *thisName;
   1.540 +	    unsigned int thisName_length;
   1.541 +
   1.542 +	    thisName = nsslowcert_dataStart(nameList, nameList_length,
   1.543 +					&thisName_length, PR_FALSE, NULL);
   1.544 +	    if (thisName == NULL) { break; }
   1.545 +	    if (nameList[0] == 0xa2) { /* DNS Name */
   1.546 +		SECItem dn;
   1.547 +	        char *emailAddr;
   1.548 +
   1.549 +		dn.data = thisName;
   1.550 +		dn.len = thisName_length;
   1.551 +		emailAddr = nsslowcert_EmailName(&dn, space, len);
   1.552 +		if (emailAddr) {
   1.553 +		    return emailAddr;
   1.554 +		}
   1.555 +	    }
   1.556 +	    if (nameList[0] == 0x81) { /* RFC 822name */
   1.557 +		char *emailAddr;
   1.558 +		emailAddr = (char *)pkcs11_copyStaticData(thisName,
   1.559 +			thisName_length+1, (unsigned char *)space,len);
   1.560 +		if (emailAddr) {
   1.561 +		    emailAddr[thisName_length] = 0;
   1.562 +		}
   1.563 +		return emailAddr;
   1.564 +	    }
   1.565 +	    nameList_length -= (thisName-nameList) + thisName_length;
   1.566 +	    nameList = thisName + thisName_length;
   1.567 +	}
   1.568 +	break;
   1.569 +    }
   1.570 +    return NULL;
   1.571 +}
   1.572 +
   1.573 +static char *
   1.574 +nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert)
   1.575 +{
   1.576 +    char *emailAddr = NULL;
   1.577 +    char *str;
   1.578 +
   1.579 +    emailAddr = nsslowcert_EmailName(&cert->derSubject,cert->emailAddrSpace,
   1.580 +					sizeof(cert->emailAddrSpace));
   1.581 +    /* couldn't find the email address in the DN, check the subject Alt name */
   1.582 +    if (!emailAddr && cert->extensions.data) {
   1.583 +	emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace,
   1.584 +					sizeof(cert->emailAddrSpace));
   1.585 +    }
   1.586 +
   1.587 +
   1.588 +    /* make it lower case */
   1.589 +    str = emailAddr;
   1.590 +    while ( str && *str ) {
   1.591 +	*str = tolower( *str );
   1.592 +	str++;
   1.593 +    }
   1.594 +    return emailAddr;
   1.595 +
   1.596 +}
   1.597 +
   1.598 +/*
   1.599 + * take a DER certificate and decode it into a certificate structure
   1.600 + */
   1.601 +NSSLOWCERTCertificate *
   1.602 +nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname)
   1.603 +{
   1.604 +    NSSLOWCERTCertificate *cert;
   1.605 +    int rv;
   1.606 +
   1.607 +    /* allocate the certificate structure */
   1.608 +    cert = nsslowcert_CreateCert();
   1.609 +    
   1.610 +    if ( !cert ) {
   1.611 +	goto loser;
   1.612 +    }
   1.613 +    
   1.614 +	/* point to passed in DER data */
   1.615 +    cert->derCert = *derSignedCert;
   1.616 +    cert->nickname = NULL;
   1.617 +    cert->certKey.data = NULL;
   1.618 +    cert->referenceCount = 1;
   1.619 +
   1.620 +    /* decode the certificate info */
   1.621 +    rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len,
   1.622 +	&cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject,
   1.623 +	&cert->validity, &cert->derSubjKeyInfo, &cert->extensions);
   1.624 +
   1.625 +    if (rv != SECSuccess) {
   1.626 +	goto loser;
   1.627 +    }
   1.628 +
   1.629 +    /* cert->subjectKeyID;	 x509v3 subject key identifier */
   1.630 +    cert->subjectKeyID.data = NULL;
   1.631 +    cert->subjectKeyID.len = 0;
   1.632 +    cert->dbEntry = NULL;
   1.633 +    cert ->trust = NULL;
   1.634 +    cert ->dbhandle = NULL;
   1.635 +
   1.636 +    /* generate and save the database key for the cert */
   1.637 +    rv = nsslowcert_KeyFromIssuerAndSNStatic(cert->certKeySpace,
   1.638 +		sizeof(cert->certKeySpace), &cert->derIssuer, 
   1.639 +		&cert->serialNumber, &cert->certKey);
   1.640 +    if ( rv ) {
   1.641 +	goto loser;
   1.642 +    }
   1.643 +
   1.644 +    /* set the nickname */
   1.645 +    if ( nickname == NULL ) {
   1.646 +	cert->nickname = NULL;
   1.647 +    } else {
   1.648 +	/* copy and install the nickname */
   1.649 +	cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace,
   1.650 +				sizeof(cert->nicknameSpace));
   1.651 +    }
   1.652 +
   1.653 +#ifdef FIXME
   1.654 +    /* initialize the subjectKeyID */
   1.655 +    rv = cert_GetKeyID(cert);
   1.656 +    if ( rv != SECSuccess ) {
   1.657 +	goto loser;
   1.658 +    }
   1.659 +#endif
   1.660 +
   1.661 +    /* set the email address */
   1.662 +    cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert);
   1.663 +    
   1.664 +    
   1.665 +    cert->referenceCount = 1;
   1.666 +    
   1.667 +    return(cert);
   1.668 +    
   1.669 +loser:
   1.670 +    if (cert) {
   1.671 +	nsslowcert_DestroyCertificate(cert);
   1.672 +    }
   1.673 +    
   1.674 +    return(0);
   1.675 +}
   1.676 +
   1.677 +char *
   1.678 +nsslowcert_FixupEmailAddr(char *emailAddr)
   1.679 +{
   1.680 +    char *retaddr;
   1.681 +    char *str;
   1.682 +
   1.683 +    if ( emailAddr == NULL ) {
   1.684 +	return(NULL);
   1.685 +    }
   1.686 +    
   1.687 +    /* copy the string */
   1.688 +    str = retaddr = PORT_Strdup(emailAddr);
   1.689 +    if ( str == NULL ) {
   1.690 +	return(NULL);
   1.691 +    }
   1.692 +    
   1.693 +    /* make it lower case */
   1.694 +    while ( *str ) {
   1.695 +	*str = tolower( *str );
   1.696 +	str++;
   1.697 +    }
   1.698 +    
   1.699 +    return(retaddr);
   1.700 +}
   1.701 +
   1.702 +
   1.703 +/*
   1.704 + * Generate a database key, based on serial number and issuer, from a
   1.705 + * DER certificate.
   1.706 + */
   1.707 +SECStatus
   1.708 +nsslowcert_KeyFromDERCert(PLArenaPool *arena, SECItem *derCert, SECItem *key)
   1.709 +{
   1.710 +    int rv;
   1.711 +    NSSLOWCERTCertKey certkey;
   1.712 +
   1.713 +    PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey));    
   1.714 +
   1.715 +    rv = nsslowcert_GetCertFields(derCert->data, derCert->len,
   1.716 +	&certkey.derIssuer, &certkey.serialNumber, NULL, NULL, 
   1.717 +	NULL, NULL, NULL);
   1.718 +
   1.719 +    if ( rv ) {
   1.720 +	goto loser;
   1.721 +    }
   1.722 +
   1.723 +    return(nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
   1.724 +				   &certkey.serialNumber, key));
   1.725 +loser:
   1.726 +    return(SECFailure);
   1.727 +}
   1.728 +
   1.729 +NSSLOWKEYPublicKey *
   1.730 +nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert)
   1.731 +{
   1.732 +    NSSLOWCERTSubjectPublicKeyInfo spki;
   1.733 +    NSSLOWKEYPublicKey *pubk;
   1.734 +    SECItem os;
   1.735 +    SECStatus rv;
   1.736 +    PLArenaPool *arena;
   1.737 +    SECOidTag tag;
   1.738 +    SECItem newDerSubjKeyInfo;
   1.739 +
   1.740 +    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
   1.741 +    if (arena == NULL)
   1.742 +        return NULL;
   1.743 +
   1.744 +    pubk = (NSSLOWKEYPublicKey *) 
   1.745 +		PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey));
   1.746 +    if (pubk == NULL) {
   1.747 +        PORT_FreeArena (arena, PR_FALSE);
   1.748 +        return NULL;
   1.749 +    }
   1.750 +
   1.751 +    pubk->arena = arena;
   1.752 +    PORT_Memset(&spki,0,sizeof(spki));
   1.753 +
   1.754 +    /* copy the DER into the arena, since Quick DER returns data that points
   1.755 +       into the DER input, which may get freed by the caller */
   1.756 +    rv = SECITEM_CopyItem(arena, &newDerSubjKeyInfo, &cert->derSubjKeyInfo);
   1.757 +    if ( rv != SECSuccess ) {
   1.758 +        PORT_FreeArena (arena, PR_FALSE);
   1.759 +        return NULL;
   1.760 +    }
   1.761 +
   1.762 +    /* we haven't bothered decoding the spki struct yet, do it now */
   1.763 +    rv = SEC_QuickDERDecodeItem(arena, &spki, 
   1.764 +		nsslowcert_SubjectPublicKeyInfoTemplate, &newDerSubjKeyInfo);
   1.765 +    if (rv != SECSuccess) {
   1.766 + 	PORT_FreeArena (arena, PR_FALSE);
   1.767 + 	return NULL;
   1.768 +    }
   1.769 +
   1.770 +    /* Convert bit string length from bits to bytes */
   1.771 +    os = spki.subjectPublicKey;
   1.772 +    DER_ConvertBitString (&os);
   1.773 +
   1.774 +    tag = SECOID_GetAlgorithmTag(&spki.algorithm);
   1.775 +    switch ( tag ) {
   1.776 +      case SEC_OID_X500_RSA_ENCRYPTION:
   1.777 +      case SEC_OID_PKCS1_RSA_ENCRYPTION:
   1.778 +        pubk->keyType = NSSLOWKEYRSAKey;
   1.779 +        prepare_low_rsa_pub_key_for_asn1(pubk);
   1.780 +        rv = SEC_QuickDERDecodeItem(arena, pubk, 
   1.781 +				nsslowcert_RSAPublicKeyTemplate, &os);
   1.782 +        if (rv == SECSuccess)
   1.783 +            return pubk;
   1.784 +        break;
   1.785 +      case SEC_OID_ANSIX9_DSA_SIGNATURE:
   1.786 +        pubk->keyType = NSSLOWKEYDSAKey;
   1.787 +        prepare_low_dsa_pub_key_for_asn1(pubk);
   1.788 +        rv = SEC_QuickDERDecodeItem(arena, pubk,
   1.789 +				 nsslowcert_DSAPublicKeyTemplate, &os);
   1.790 +        if (rv == SECSuccess) return pubk;
   1.791 +        break;
   1.792 +      case SEC_OID_X942_DIFFIE_HELMAN_KEY:
   1.793 +        pubk->keyType = NSSLOWKEYDHKey;
   1.794 +        prepare_low_dh_pub_key_for_asn1(pubk);
   1.795 +        rv = SEC_QuickDERDecodeItem(arena, pubk,
   1.796 +				 nsslowcert_DHPublicKeyTemplate, &os);
   1.797 +        if (rv == SECSuccess) return pubk;
   1.798 +        break;
   1.799 +#ifndef NSS_DISABLE_ECC
   1.800 +      case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
   1.801 +        pubk->keyType = NSSLOWKEYECKey;
   1.802 +	/* Since PKCS#11 directly takes the DER encoding of EC params
   1.803 +	 * and public value, we don't need any decoding here.
   1.804 +	 */
   1.805 +        rv = SECITEM_CopyItem(arena, &pubk->u.ec.ecParams.DEREncoding, 
   1.806 +	    &spki.algorithm.parameters);
   1.807 +        if ( rv != SECSuccess )
   1.808 +            break;	
   1.809 +
   1.810 +	/* Fill out the rest of the ecParams structure 
   1.811 +	 * based on the encoded params
   1.812 +	 */
   1.813 +	if (LGEC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding,
   1.814 +	    &pubk->u.ec.ecParams) != SECSuccess) 
   1.815 +	    break;
   1.816 +
   1.817 +        rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &os);
   1.818 +	if (rv == SECSuccess) return pubk;
   1.819 +        break;
   1.820 +#endif /* NSS_DISABLE_ECC */
   1.821 +      default:
   1.822 +        rv = SECFailure;
   1.823 +        break;
   1.824 +    }
   1.825 +
   1.826 +    lg_nsslowkey_DestroyPublicKey (pubk);
   1.827 +    return NULL;
   1.828 +}
   1.829 +

mercurial