Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / certhigh / certreq.c
blob148b71746cee9519c54308389fe493516d60a633
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "cert.h"
38 #include "certt.h"
39 #include "secder.h"
40 #include "key.h"
41 #include "secitem.h"
42 #include "secasn1.h"
43 #include "secerr.h"
45 const SEC_ASN1Template CERT_AttributeTemplate[] = {
46 { SEC_ASN1_SEQUENCE,
47 0, NULL, sizeof(CERTAttribute) },
48 { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
49 { SEC_ASN1_SET_OF, offsetof(CERTAttribute, attrValue),
50 SEC_AnyTemplate },
51 { 0 }
54 const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
55 { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
58 const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
59 { SEC_ASN1_SEQUENCE,
60 0, NULL, sizeof(CERTCertificateRequest) },
61 { SEC_ASN1_INTEGER,
62 offsetof(CERTCertificateRequest,version) },
63 { SEC_ASN1_INLINE,
64 offsetof(CERTCertificateRequest,subject),
65 CERT_NameTemplate },
66 { SEC_ASN1_INLINE,
67 offsetof(CERTCertificateRequest,subjectPublicKeyInfo),
68 CERT_SubjectPublicKeyInfoTemplate },
69 { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
70 offsetof(CERTCertificateRequest,attributes),
71 CERT_SetOfAttributeTemplate },
72 { 0 }
75 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
77 CERTCertificate *
78 CERT_CreateCertificate(unsigned long serialNumber,
79 CERTName *issuer,
80 CERTValidity *validity,
81 CERTCertificateRequest *req)
83 CERTCertificate *c;
84 int rv;
85 PRArenaPool *arena;
87 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
89 if ( !arena ) {
90 return(0);
93 c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
95 if (c) {
96 c->referenceCount = 1;
97 c->arena = arena;
100 * Default is a plain version 1.
101 * If extensions are added, it will get changed as appropriate.
103 rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
104 if (rv) goto loser;
106 rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
107 if (rv) goto loser;
109 rv = CERT_CopyName(arena, &c->issuer, issuer);
110 if (rv) goto loser;
112 rv = CERT_CopyValidity(arena, &c->validity, validity);
113 if (rv) goto loser;
115 rv = CERT_CopyName(arena, &c->subject, &req->subject);
116 if (rv) goto loser;
117 rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
118 &req->subjectPublicKeyInfo);
119 if (rv) goto loser;
121 return c;
123 loser:
124 CERT_DestroyCertificate(c);
125 return 0;
128 /************************************************************************/
129 /* It's clear from the comments that the original author of this
130 * function expected the template for certificate requests to treat
131 * the attributes as a SET OF ANY. This function expected to be
132 * passed an array of SECItems each of which contained an already encoded
133 * Attribute. But the cert request template does not treat the
134 * Attributes as a SET OF ANY, and AFAIK never has. Instead the template
135 * encodes attributes as a SET OF xxxxxxx. That is, it expects to encode
136 * each of the Attributes, not have them pre-encoded. Consequently an
137 * array of SECItems containing encoded Attributes is of no value to this
138 * function. But we cannot change the signature of this public function.
139 * It must continue to take SECItems.
141 * I have recoded this function so that each SECItem contains an
142 * encoded cert extension. The encoded cert extensions form the list for the
143 * single attribute of the cert request. In this implementation there is at most
144 * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
147 CERTCertificateRequest *
148 CERT_CreateCertificateRequest(CERTName *subject,
149 CERTSubjectPublicKeyInfo *spki,
150 SECItem **attributes)
152 CERTCertificateRequest *certreq;
153 PRArenaPool *arena;
154 CERTAttribute * attribute;
155 SECOidData * oidData;
156 SECStatus rv;
157 int i = 0;
159 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
160 if ( arena == NULL ) {
161 return NULL;
164 certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
165 if (!certreq) {
166 PORT_FreeArena(arena, PR_FALSE);
167 return NULL;
169 /* below here it is safe to goto loser */
171 certreq->arena = arena;
173 rv = DER_SetUInteger(arena, &certreq->version,
174 SEC_CERTIFICATE_REQUEST_VERSION);
175 if (rv != SECSuccess)
176 goto loser;
178 rv = CERT_CopyName(arena, &certreq->subject, subject);
179 if (rv != SECSuccess)
180 goto loser;
182 rv = SECKEY_CopySubjectPublicKeyInfo(arena,
183 &certreq->subjectPublicKeyInfo,
184 spki);
185 if (rv != SECSuccess)
186 goto loser;
188 certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2);
189 if(!certreq->attributes)
190 goto loser;
192 /* Copy over attribute information */
193 if (!attributes || !attributes[0]) {
195 ** Invent empty attribute information. According to the
196 ** pkcs#10 spec, attributes has this ASN.1 type:
198 ** attributes [0] IMPLICIT Attributes
200 ** Which means, we should create a NULL terminated list
201 ** with the first entry being NULL;
203 certreq->attributes[0] = NULL;
204 return certreq;
207 /* allocate space for attributes */
208 attribute = PORT_ArenaZNew(arena, CERTAttribute);
209 if (!attribute)
210 goto loser;
212 oidData = SECOID_FindOIDByTag( SEC_OID_PKCS9_EXTENSION_REQUEST );
213 PORT_Assert(oidData);
214 if (!oidData)
215 goto loser;
216 rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
217 if (rv != SECSuccess)
218 goto loser;
220 for (i = 0; attributes[i] != NULL ; i++)
222 attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i+1);
223 if (!attribute->attrValue)
224 goto loser;
226 /* copy attributes */
227 for (i = 0; attributes[i]; i++) {
229 ** Attributes are a SetOf Attribute which implies
230 ** lexigraphical ordering. It is assumes that the
231 ** attributes are passed in sorted. If we need to
232 ** add functionality to sort them, there is an
233 ** example in the PKCS 7 code.
235 attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
236 if(!attribute->attrValue[i])
237 goto loser;
240 certreq->attributes[0] = attribute;
242 return certreq;
244 loser:
245 CERT_DestroyCertificateRequest(certreq);
246 return NULL;
249 void
250 CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
252 if (req && req->arena) {
253 PORT_FreeArena(req->arena, PR_FALSE);
255 return;
258 static void
259 setCRExt(void *o, CERTCertExtension **exts)
261 ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
265 ** Set up to start gathering cert extensions for a cert request.
266 ** The list is created as CertExtensions and converted to an
267 ** attribute list by CERT_FinishCRAttributes().
269 extern void *cert_StartExtensions(void *owner, PRArenaPool *ownerArena,
270 void (*setExts)(void *object, CERTCertExtension **exts));
271 void *
272 CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
274 return (cert_StartExtensions ((void *)req, req->arena, setCRExt));
278 ** At entry req->attributes actually contains an list of cert extensions--
279 ** req-attributes is overloaded until the list is DER encoded (the first
280 ** ...EncodeItem() below).
281 ** We turn this into an attribute list by encapsulating it
282 ** in a PKCS 10 Attribute structure
284 SECStatus
285 CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
286 { SECItem *extlist;
287 SECOidData *oidrec;
288 CERTAttribute *attribute;
290 if (!req || !req->arena) {
291 PORT_SetError(SEC_ERROR_INVALID_ARGS);
292 return SECFailure;
294 if (req->attributes == NULL || req->attributes[0] == NULL)
295 return SECSuccess;
297 extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
298 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
299 if (extlist == NULL)
300 return(SECFailure);
302 oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
303 if (oidrec == NULL)
304 return SECFailure;
306 /* now change the list of cert extensions into a list of attributes
308 req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2);
310 attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
312 if (req->attributes == NULL || attribute == NULL ||
313 SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
314 PORT_SetError(SEC_ERROR_NO_MEMORY);
315 return SECFailure;
317 attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2);
319 if (attribute->attrValue == NULL)
320 return SECFailure;
322 attribute->attrValue[0] = extlist;
323 attribute->attrValue[1] = NULL;
324 req->attributes[0] = attribute;
325 req->attributes[1] = NULL;
327 return SECSuccess;
330 SECStatus
331 CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
332 CERTCertExtension ***exts)
334 if (req == NULL || exts == NULL) {
335 PORT_SetError(SEC_ERROR_INVALID_ARGS);
336 return SECFailure;
339 if (req->attributes == NULL || *req->attributes == NULL)
340 return SECSuccess;
342 if ((*req->attributes)->attrValue == NULL) {
343 PORT_SetError(SEC_ERROR_INVALID_ARGS);
344 return SECFailure;
347 return(SEC_ASN1DecodeItem(req->arena, exts,
348 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
349 (*req->attributes)->attrValue[0]));