Back to index

lightning-sunbird  0.9+nobinonly
certreq.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "cert.h"
00038 #include "certt.h"
00039 #include "secder.h"
00040 #include "key.h"
00041 #include "secitem.h"
00042 #include "secasn1.h"
00043 #include "secerr.h"
00044 
00045 const SEC_ASN1Template CERT_AttributeTemplate[] = {
00046     { SEC_ASN1_SEQUENCE,
00047        0, NULL, sizeof(CERTAttribute) },
00048     { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
00049     { SEC_ASN1_SET_OF, offsetof(CERTAttribute, attrValue),
00050        SEC_AnyTemplate },
00051     { 0 }
00052 };
00053 
00054 const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
00055     { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
00056 };
00057 
00058 const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
00059     { SEC_ASN1_SEQUENCE,
00060          0, NULL, sizeof(CERTCertificateRequest) },
00061     { SEC_ASN1_INTEGER,
00062          offsetof(CERTCertificateRequest,version) },
00063     { SEC_ASN1_INLINE,
00064          offsetof(CERTCertificateRequest,subject),
00065          CERT_NameTemplate },
00066     { SEC_ASN1_INLINE,
00067          offsetof(CERTCertificateRequest,subjectPublicKeyInfo),
00068          CERT_SubjectPublicKeyInfoTemplate },
00069     { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
00070          offsetof(CERTCertificateRequest,attributes), 
00071          CERT_SetOfAttributeTemplate },
00072     { 0 }
00073 };
00074 
00075 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
00076 
00077 CERTCertificate *
00078 CERT_CreateCertificate(unsigned long serialNumber,
00079                     CERTName *issuer,
00080                     CERTValidity *validity,
00081                     CERTCertificateRequest *req)
00082 {
00083     CERTCertificate *c;
00084     int rv;
00085     PRArenaPool *arena;
00086     
00087     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00088     
00089     if ( !arena ) {
00090        return(0);
00091     }
00092 
00093     c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
00094     
00095     if (c) {
00096        c->referenceCount = 1;
00097        c->arena = arena;
00098 
00099        /*
00100         * Default is a plain version 1.
00101         * If extensions are added, it will get changed as appropriate.
00102         */
00103        rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
00104        if (rv) goto loser;
00105 
00106        rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
00107        if (rv) goto loser;
00108 
00109        rv = CERT_CopyName(arena, &c->issuer, issuer);
00110        if (rv) goto loser;
00111 
00112        rv = CERT_CopyValidity(arena, &c->validity, validity);
00113        if (rv) goto loser;
00114 
00115        rv = CERT_CopyName(arena, &c->subject, &req->subject);
00116        if (rv) goto loser;
00117        rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
00118                                      &req->subjectPublicKeyInfo);
00119        if (rv) goto loser;
00120     }
00121     return c;
00122 
00123   loser:
00124     CERT_DestroyCertificate(c);
00125     return 0;
00126 }
00127 
00128 /************************************************************************/
00129 /* It's clear from the comments that the original author of this 
00130  * function expected the template for certificate requests to treat
00131  * the attributes as a SET OF ANY.  This function expected to be 
00132  * passed an array of SECItems each of which contained an already encoded
00133  * Attribute.  But the cert request template does not treat the 
00134  * Attributes as a SET OF ANY, and AFAIK never has.  Instead the template
00135  * encodes attributes as a SET OF xxxxxxx.  That is, it expects to encode
00136  * each of the Attributes, not have them pre-encoded.  Consequently an 
00137  * array of SECItems containing encoded Attributes is of no value to this 
00138  * function.  But we cannot change the signature of this public function.
00139  * It must continue to take SECItems.
00140  *
00141  * I have recoded this function so that each SECItem contains an 
00142  * encoded cert extension.  The encoded cert extensions form the list for the
00143  * single attribute of the cert request. In this implementation there is at most
00144  * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
00145  */
00146 
00147 CERTCertificateRequest *
00148 CERT_CreateCertificateRequest(CERTName *subject,
00149                           CERTSubjectPublicKeyInfo *spki,
00150                           SECItem **attributes)
00151 {
00152     CERTCertificateRequest *certreq;
00153     PRArenaPool *arena;
00154     CERTAttribute * attribute;
00155     SECOidData * oidData;
00156     SECStatus rv;
00157     int i = 0;
00158 
00159     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00160     if ( arena == NULL ) {
00161        return NULL;
00162     }
00163     
00164     certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
00165     if (!certreq) {
00166        PORT_FreeArena(arena, PR_FALSE);
00167        return NULL;
00168     }
00169     /* below here it is safe to goto loser */
00170 
00171     certreq->arena = arena;
00172     
00173     rv = DER_SetUInteger(arena, &certreq->version,
00174                       SEC_CERTIFICATE_REQUEST_VERSION);
00175     if (rv != SECSuccess)
00176        goto loser;
00177 
00178     rv = CERT_CopyName(arena, &certreq->subject, subject);
00179     if (rv != SECSuccess)
00180        goto loser;
00181 
00182     rv = SECKEY_CopySubjectPublicKeyInfo(arena,
00183                                   &certreq->subjectPublicKeyInfo,
00184                                   spki);
00185     if (rv != SECSuccess)
00186        goto loser;
00187 
00188     certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2);
00189     if(!certreq->attributes) 
00190        goto loser;
00191 
00192     /* Copy over attribute information */
00193     if (!attributes || !attributes[0]) {
00194        /*
00195         ** Invent empty attribute information. According to the
00196         ** pkcs#10 spec, attributes has this ASN.1 type:
00197         **
00198         ** attributes [0] IMPLICIT Attributes
00199         ** 
00200         ** Which means, we should create a NULL terminated list
00201         ** with the first entry being NULL;
00202         */
00203        certreq->attributes[0] = NULL;
00204        return certreq;
00205     }  
00206 
00207     /* allocate space for attributes */
00208     attribute = PORT_ArenaZNew(arena, CERTAttribute);
00209     if (!attribute) 
00210        goto loser;
00211 
00212     oidData = SECOID_FindOIDByTag( SEC_OID_PKCS9_EXTENSION_REQUEST );
00213     PORT_Assert(oidData);
00214     if (!oidData)
00215        goto loser;
00216     rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
00217     if (rv != SECSuccess)
00218        goto loser;
00219 
00220     for (i = 0; attributes[i] != NULL ; i++) 
00221        ;
00222     attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i+1);
00223     if (!attribute->attrValue) 
00224        goto loser;
00225 
00226     /* copy attributes */
00227     for (i = 0; attributes[i]; i++) {
00228        /*
00229        ** Attributes are a SetOf Attribute which implies
00230        ** lexigraphical ordering.  It is assumes that the
00231        ** attributes are passed in sorted.  If we need to
00232        ** add functionality to sort them, there is an
00233        ** example in the PKCS 7 code.
00234        */
00235        attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
00236        if(!attribute->attrValue[i]) 
00237            goto loser;
00238     }
00239 
00240     certreq->attributes[0] = attribute;
00241 
00242     return certreq;
00243 
00244 loser:
00245     CERT_DestroyCertificateRequest(certreq);
00246     return NULL;
00247 }
00248 
00249 void
00250 CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
00251 {
00252     if (req && req->arena) {
00253        PORT_FreeArena(req->arena, PR_FALSE);
00254     }
00255     return;
00256 }
00257 
00258 static void
00259 setCRExt(void *o, CERTCertExtension **exts)
00260 {
00261     ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
00262 }
00263 
00264 /*
00265 ** Set up to start gathering cert extensions for a cert request.
00266 ** The list is created as CertExtensions and converted to an
00267 ** attribute list by CERT_FinishCRAttributes().
00268  */
00269 extern void *cert_StartExtensions(void *owner, PRArenaPool *ownerArena,
00270                        void (*setExts)(void *object, CERTCertExtension **exts));
00271 void *
00272 CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
00273 {
00274     return (cert_StartExtensions ((void *)req, req->arena, setCRExt));
00275 }
00276 
00277 /*
00278 ** At entry req->attributes actually contains an list of cert extensions--
00279 ** req-attributes is overloaded until the list is DER encoded (the first
00280 ** ...EncodeItem() below).
00281 ** We turn this into an attribute list by encapsulating it
00282 ** in a PKCS 10 Attribute structure
00283  */
00284 SECStatus
00285 CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
00286 {   SECItem *extlist;
00287     SECOidData *oidrec;
00288     CERTAttribute *attribute;
00289    
00290     if (!req || !req->arena) {
00291        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00292         return SECFailure;
00293     }
00294     if (req->attributes == NULL || req->attributes[0] == NULL)
00295         return SECSuccess;
00296 
00297     extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
00298                             SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
00299     if (extlist == NULL)
00300         return(SECFailure);
00301 
00302     oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
00303     if (oidrec == NULL)
00304        return SECFailure;
00305 
00306     /* now change the list of cert extensions into a list of attributes
00307      */
00308     req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2);
00309 
00310     attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
00311     
00312     if (req->attributes == NULL || attribute == NULL ||
00313         SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
00314         PORT_SetError(SEC_ERROR_NO_MEMORY);
00315        return SECFailure;
00316     }
00317     attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2);
00318 
00319     if (attribute->attrValue == NULL)
00320         return SECFailure;
00321 
00322     attribute->attrValue[0] = extlist;
00323     attribute->attrValue[1] = NULL;
00324     req->attributes[0] = attribute;
00325     req->attributes[1] = NULL;
00326 
00327     return SECSuccess;
00328 }
00329 
00330 SECStatus
00331 CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
00332                                         CERTCertExtension ***exts)
00333 {
00334     if (req == NULL || exts == NULL) {
00335        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00336         return SECFailure;
00337     }
00338     
00339     if (req->attributes == NULL || *req->attributes == NULL)
00340         return SECSuccess;
00341     
00342     if ((*req->attributes)->attrValue == NULL) {
00343        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00344         return SECFailure;
00345     }
00346 
00347     return(SEC_ASN1DecodeItem(req->arena, exts, 
00348             SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
00349             (*req->attributes)->attrValue[0]));
00350 }