security/nss/lib/certhigh/certreq.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/certhigh/certreq.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,324 @@
     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 +#include "cert.h"
     1.9 +#include "certt.h"
    1.10 +#include "secder.h"
    1.11 +#include "key.h"
    1.12 +#include "secitem.h"
    1.13 +#include "secasn1.h"
    1.14 +#include "secerr.h"
    1.15 +
    1.16 +SEC_ASN1_MKSUB(SEC_AnyTemplate)
    1.17 +
    1.18 +const SEC_ASN1Template CERT_AttributeTemplate[] = {
    1.19 +    { SEC_ASN1_SEQUENCE,
    1.20 +	0, NULL, sizeof(CERTAttribute) },
    1.21 +    { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
    1.22 +    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
    1.23 +	SEC_ASN1_SUB(SEC_AnyTemplate) },
    1.24 +    { 0 }
    1.25 +};
    1.26 +
    1.27 +const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
    1.28 +    { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
    1.29 +};
    1.30 +
    1.31 +const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
    1.32 +    { SEC_ASN1_SEQUENCE,
    1.33 +	  0, NULL, sizeof(CERTCertificateRequest) },
    1.34 +    { SEC_ASN1_INTEGER,
    1.35 +	  offsetof(CERTCertificateRequest,version) },
    1.36 +    { SEC_ASN1_INLINE,
    1.37 +	  offsetof(CERTCertificateRequest,subject),
    1.38 +	  CERT_NameTemplate },
    1.39 +    { SEC_ASN1_INLINE,
    1.40 +	  offsetof(CERTCertificateRequest,subjectPublicKeyInfo),
    1.41 +	  CERT_SubjectPublicKeyInfoTemplate },
    1.42 +    { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
    1.43 +	  offsetof(CERTCertificateRequest,attributes), 
    1.44 +	  CERT_SetOfAttributeTemplate },
    1.45 +    { 0 }
    1.46 +};
    1.47 +
    1.48 +SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
    1.49 +
    1.50 +CERTCertificate *
    1.51 +CERT_CreateCertificate(unsigned long serialNumber,
    1.52 +		      CERTName *issuer,
    1.53 +		      CERTValidity *validity,
    1.54 +		      CERTCertificateRequest *req)
    1.55 +{
    1.56 +    CERTCertificate *c;
    1.57 +    int rv;
    1.58 +    PLArenaPool *arena;
    1.59 +    
    1.60 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    1.61 +    
    1.62 +    if ( !arena ) {
    1.63 +	return(0);
    1.64 +    }
    1.65 +
    1.66 +    c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
    1.67 +    
    1.68 +    if (!c) {
    1.69 +	PORT_FreeArena(arena, PR_FALSE);
    1.70 +	return 0;
    1.71 +    }
    1.72 +
    1.73 +    c->referenceCount = 1;
    1.74 +    c->arena = arena;
    1.75 +
    1.76 +    /*
    1.77 +     * Default is a plain version 1.
    1.78 +     * If extensions are added, it will get changed as appropriate.
    1.79 +     */
    1.80 +    rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
    1.81 +    if (rv) goto loser;
    1.82 +
    1.83 +    rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
    1.84 +    if (rv) goto loser;
    1.85 +
    1.86 +    rv = CERT_CopyName(arena, &c->issuer, issuer);
    1.87 +    if (rv) goto loser;
    1.88 +
    1.89 +    rv = CERT_CopyValidity(arena, &c->validity, validity);
    1.90 +    if (rv) goto loser;
    1.91 +
    1.92 +    rv = CERT_CopyName(arena, &c->subject, &req->subject);
    1.93 +    if (rv) goto loser;
    1.94 +    rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
    1.95 +					 &req->subjectPublicKeyInfo);
    1.96 +    if (rv) goto loser;
    1.97 +
    1.98 +    return c;
    1.99 +
   1.100 + loser:
   1.101 +    CERT_DestroyCertificate(c);
   1.102 +    return 0;
   1.103 +}
   1.104 +
   1.105 +/************************************************************************/
   1.106 +/* It's clear from the comments that the original author of this 
   1.107 + * function expected the template for certificate requests to treat
   1.108 + * the attributes as a SET OF ANY.  This function expected to be 
   1.109 + * passed an array of SECItems each of which contained an already encoded
   1.110 + * Attribute.  But the cert request template does not treat the 
   1.111 + * Attributes as a SET OF ANY, and AFAIK never has.  Instead the template
   1.112 + * encodes attributes as a SET OF xxxxxxx.  That is, it expects to encode
   1.113 + * each of the Attributes, not have them pre-encoded.  Consequently an 
   1.114 + * array of SECItems containing encoded Attributes is of no value to this 
   1.115 + * function.  But we cannot change the signature of this public function.
   1.116 + * It must continue to take SECItems.
   1.117 + *
   1.118 + * I have recoded this function so that each SECItem contains an 
   1.119 + * encoded cert extension.  The encoded cert extensions form the list for the
   1.120 + * single attribute of the cert request. In this implementation there is at most
   1.121 + * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
   1.122 + */
   1.123 +
   1.124 +CERTCertificateRequest *
   1.125 +CERT_CreateCertificateRequest(CERTName *subject,
   1.126 +			     CERTSubjectPublicKeyInfo *spki,
   1.127 +			     SECItem **attributes)
   1.128 +{
   1.129 +    CERTCertificateRequest *certreq;
   1.130 +    PLArenaPool *arena;
   1.131 +    CERTAttribute * attribute;
   1.132 +    SECOidData * oidData;
   1.133 +    SECStatus rv;
   1.134 +    int i = 0;
   1.135 +
   1.136 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.137 +    if ( arena == NULL ) {
   1.138 +	return NULL;
   1.139 +    }
   1.140 +    
   1.141 +    certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
   1.142 +    if (!certreq) {
   1.143 +	PORT_FreeArena(arena, PR_FALSE);
   1.144 +	return NULL;
   1.145 +    }
   1.146 +    /* below here it is safe to goto loser */
   1.147 +
   1.148 +    certreq->arena = arena;
   1.149 +    
   1.150 +    rv = DER_SetUInteger(arena, &certreq->version,
   1.151 +			 SEC_CERTIFICATE_REQUEST_VERSION);
   1.152 +    if (rv != SECSuccess)
   1.153 +	goto loser;
   1.154 +
   1.155 +    rv = CERT_CopyName(arena, &certreq->subject, subject);
   1.156 +    if (rv != SECSuccess)
   1.157 +	goto loser;
   1.158 +
   1.159 +    rv = SECKEY_CopySubjectPublicKeyInfo(arena,
   1.160 +				      &certreq->subjectPublicKeyInfo,
   1.161 +				      spki);
   1.162 +    if (rv != SECSuccess)
   1.163 +	goto loser;
   1.164 +
   1.165 +    certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2);
   1.166 +    if(!certreq->attributes) 
   1.167 +	goto loser;
   1.168 +
   1.169 +    /* Copy over attribute information */
   1.170 +    if (!attributes || !attributes[0]) {
   1.171 +	/*
   1.172 +	 ** Invent empty attribute information. According to the
   1.173 +	 ** pkcs#10 spec, attributes has this ASN.1 type:
   1.174 +	 **
   1.175 +	 ** attributes [0] IMPLICIT Attributes
   1.176 +	 ** 
   1.177 +	 ** Which means, we should create a NULL terminated list
   1.178 +	 ** with the first entry being NULL;
   1.179 +	 */
   1.180 +	certreq->attributes[0] = NULL;
   1.181 +	return certreq;
   1.182 +    }	
   1.183 +
   1.184 +    /* allocate space for attributes */
   1.185 +    attribute = PORT_ArenaZNew(arena, CERTAttribute);
   1.186 +    if (!attribute) 
   1.187 +	goto loser;
   1.188 +
   1.189 +    oidData = SECOID_FindOIDByTag( SEC_OID_PKCS9_EXTENSION_REQUEST );
   1.190 +    PORT_Assert(oidData);
   1.191 +    if (!oidData)
   1.192 +	goto loser;
   1.193 +    rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
   1.194 +    if (rv != SECSuccess)
   1.195 +	goto loser;
   1.196 +
   1.197 +    for (i = 0; attributes[i] != NULL ; i++) 
   1.198 +	;
   1.199 +    attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i+1);
   1.200 +    if (!attribute->attrValue) 
   1.201 +	goto loser;
   1.202 +
   1.203 +    /* copy attributes */
   1.204 +    for (i = 0; attributes[i]; i++) {
   1.205 +	/*
   1.206 +	** Attributes are a SetOf Attribute which implies
   1.207 +	** lexigraphical ordering.  It is assumes that the
   1.208 +	** attributes are passed in sorted.  If we need to
   1.209 +	** add functionality to sort them, there is an
   1.210 +	** example in the PKCS 7 code.
   1.211 +	*/
   1.212 +	attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
   1.213 +	if(!attribute->attrValue[i]) 
   1.214 +	    goto loser;
   1.215 +    }
   1.216 +
   1.217 +    certreq->attributes[0] = attribute;
   1.218 +
   1.219 +    return certreq;
   1.220 +
   1.221 +loser:
   1.222 +    CERT_DestroyCertificateRequest(certreq);
   1.223 +    return NULL;
   1.224 +}
   1.225 +
   1.226 +void
   1.227 +CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
   1.228 +{
   1.229 +    if (req && req->arena) {
   1.230 +	PORT_FreeArena(req->arena, PR_FALSE);
   1.231 +    }
   1.232 +    return;
   1.233 +}
   1.234 +
   1.235 +static void
   1.236 +setCRExt(void *o, CERTCertExtension **exts)
   1.237 +{
   1.238 +    ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
   1.239 +}
   1.240 +
   1.241 +/*
   1.242 +** Set up to start gathering cert extensions for a cert request.
   1.243 +** The list is created as CertExtensions and converted to an
   1.244 +** attribute list by CERT_FinishCRAttributes().
   1.245 + */
   1.246 +extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
   1.247 +                       void (*setExts)(void *object, CERTCertExtension **exts));
   1.248 +void *
   1.249 +CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
   1.250 +{
   1.251 +    return (cert_StartExtensions ((void *)req, req->arena, setCRExt));
   1.252 +}
   1.253 +
   1.254 +/*
   1.255 +** At entry req->attributes actually contains an list of cert extensions--
   1.256 +** req-attributes is overloaded until the list is DER encoded (the first
   1.257 +** ...EncodeItem() below).
   1.258 +** We turn this into an attribute list by encapsulating it
   1.259 +** in a PKCS 10 Attribute structure
   1.260 + */
   1.261 +SECStatus
   1.262 +CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
   1.263 +{   SECItem *extlist;
   1.264 +    SECOidData *oidrec;
   1.265 +    CERTAttribute *attribute;
   1.266 +   
   1.267 +    if (!req || !req->arena) {
   1.268 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.269 +        return SECFailure;
   1.270 +    }
   1.271 +    if (req->attributes == NULL || req->attributes[0] == NULL)
   1.272 +        return SECSuccess;
   1.273 +
   1.274 +    extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
   1.275 +                            SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
   1.276 +    if (extlist == NULL)
   1.277 +        return(SECFailure);
   1.278 +
   1.279 +    oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
   1.280 +    if (oidrec == NULL)
   1.281 +	return SECFailure;
   1.282 +
   1.283 +    /* now change the list of cert extensions into a list of attributes
   1.284 +     */
   1.285 +    req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2);
   1.286 +
   1.287 +    attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
   1.288 +    
   1.289 +    if (req->attributes == NULL || attribute == NULL ||
   1.290 +        SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
   1.291 +        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.292 +	return SECFailure;
   1.293 +    }
   1.294 +    attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2);
   1.295 +
   1.296 +    if (attribute->attrValue == NULL)
   1.297 +        return SECFailure;
   1.298 +
   1.299 +    attribute->attrValue[0] = extlist;
   1.300 +    attribute->attrValue[1] = NULL;
   1.301 +    req->attributes[0] = attribute;
   1.302 +    req->attributes[1] = NULL;
   1.303 +
   1.304 +    return SECSuccess;
   1.305 +}
   1.306 +
   1.307 +SECStatus
   1.308 +CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
   1.309 +                                        CERTCertExtension ***exts)
   1.310 +{
   1.311 +    if (req == NULL || exts == NULL) {
   1.312 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.313 +        return SECFailure;
   1.314 +    }
   1.315 +    
   1.316 +    if (req->attributes == NULL || *req->attributes == NULL)
   1.317 +        return SECSuccess;
   1.318 +    
   1.319 +    if ((*req->attributes)->attrValue == NULL) {
   1.320 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.321 +        return SECFailure;
   1.322 +    }
   1.323 +
   1.324 +    return(SEC_ASN1DecodeItem(req->arena, exts, 
   1.325 +            SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
   1.326 +            (*req->attributes)->attrValue[0]));
   1.327 +}

mercurial