security/nss/lib/crmf/crmfreq.c

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:55f4aae9d58a
1 /* -*- Mode: C; tab-width: 8 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "crmf.h"
7 #include "crmfi.h"
8 #include "keyhi.h"
9 #include "secder.h"
10
11 /*
12 * Macro that returns PR_TRUE if the pointer is not NULL.
13 * If the pointer is NULL, then the macro will return PR_FALSE.
14 */
15 #define IS_NOT_NULL(ptr) ((ptr) == NULL) ? PR_FALSE : PR_TRUE
16
17 const unsigned char hexTrue = 0xff;
18 const unsigned char hexFalse = 0x00;
19
20
21 SECStatus
22 crmf_encode_integer(PLArenaPool *poolp, SECItem *dest, long value)
23 {
24 SECItem *dummy;
25
26 dummy = SEC_ASN1EncodeInteger(poolp, dest, value);
27 PORT_Assert (dummy == dest);
28 if (dummy == NULL) {
29 return SECFailure;
30 }
31 return SECSuccess;
32 }
33
34 SECStatus
35 crmf_encode_unsigned_integer(PLArenaPool *poolp, SECItem *dest,
36 unsigned long value)
37 {
38 SECItem *dummy;
39
40 dummy = SEC_ASN1EncodeUnsignedInteger(poolp, dest, value);
41 PORT_Assert (dummy == dest);
42 if (dummy != dest) {
43 return SECFailure;
44 }
45 return SECSuccess;
46 }
47
48 static SECStatus
49 crmf_copy_secitem (PLArenaPool *poolp, SECItem *dest, SECItem *src)
50 {
51 return SECITEM_CopyItem (poolp, dest, src);
52 }
53
54 PRBool
55 CRMF_DoesRequestHaveField (CRMFCertRequest *inCertReq,
56 CRMFCertTemplateField inField)
57 {
58
59 PORT_Assert(inCertReq != NULL);
60 if (inCertReq == NULL) {
61 return PR_FALSE;
62 }
63 switch (inField) {
64 case crmfVersion:
65 return inCertReq->certTemplate.version.data != NULL;
66 case crmfSerialNumber:
67 return inCertReq->certTemplate.serialNumber.data != NULL;
68 case crmfSigningAlg:
69 return inCertReq->certTemplate.signingAlg != NULL;
70 case crmfIssuer:
71 return inCertReq->certTemplate.issuer != NULL;
72 case crmfValidity:
73 return inCertReq->certTemplate.validity != NULL;
74 case crmfSubject:
75 return inCertReq->certTemplate.subject != NULL;
76 case crmfPublicKey:
77 return inCertReq->certTemplate.publicKey != NULL;
78 case crmfIssuerUID:
79 return inCertReq->certTemplate.issuerUID.data != NULL;
80 case crmfSubjectUID:
81 return inCertReq->certTemplate.subjectUID.data != NULL;
82 case crmfExtension:
83 return CRMF_CertRequestGetNumberOfExtensions(inCertReq) != 0;
84 }
85 return PR_FALSE;
86 }
87
88 CRMFCertRequest *
89 CRMF_CreateCertRequest (PRUint32 inRequestID)
90 {
91 PLArenaPool *poolp;
92 CRMFCertRequest *certReq;
93 SECStatus rv;
94
95 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
96 if (poolp == NULL) {
97 goto loser;
98 }
99
100 certReq=PORT_ArenaZNew(poolp,CRMFCertRequest);
101 if (certReq == NULL) {
102 goto loser;
103 }
104
105 certReq->poolp = poolp;
106 certReq->requestID = inRequestID;
107
108 rv = crmf_encode_unsigned_integer(poolp, &(certReq->certReqId),
109 inRequestID);
110 if (rv != SECSuccess) {
111 goto loser;
112 }
113
114 return certReq;
115 loser:
116 if (poolp) {
117 PORT_FreeArena(poolp, PR_FALSE);
118 }
119 return NULL;
120 }
121
122 SECStatus
123 CRMF_DestroyCertRequest(CRMFCertRequest *inCertReq)
124 {
125 PORT_Assert(inCertReq != NULL);
126 if (inCertReq != NULL) {
127 if (inCertReq->certTemplate.extensions) {
128 PORT_Free(inCertReq->certTemplate.extensions);
129 }
130 if (inCertReq->controls) {
131 /* Right now we don't support EnveloppedData option,
132 * so we won't go through and delete each occurrence of
133 * an EnveloppedData in the control.
134 */
135 PORT_Free(inCertReq->controls);
136 }
137 if (inCertReq->poolp) {
138 PORT_FreeArena(inCertReq->poolp, PR_TRUE);
139 }
140 }
141 return SECSuccess;
142 }
143
144 static SECStatus
145 crmf_template_add_version(PLArenaPool *poolp, SECItem *dest, long version)
146 {
147 return (crmf_encode_integer(poolp, dest, version));
148 }
149
150 static SECStatus
151 crmf_template_add_serialnumber(PLArenaPool *poolp, SECItem *dest, long serial)
152 {
153 return (crmf_encode_integer(poolp, dest, serial));
154 }
155
156 SECStatus
157 crmf_template_copy_secalg (PLArenaPool *poolp, SECAlgorithmID **dest,
158 SECAlgorithmID* src)
159 {
160 SECStatus rv;
161 void *mark = NULL;
162 SECAlgorithmID *mySecAlg;
163
164 if (!poolp) {
165 PORT_SetError(SEC_ERROR_INVALID_ARGS);
166 return SECFailure;
167 }
168
169 mark = PORT_ArenaMark(poolp);
170 *dest = mySecAlg = PORT_ArenaZNew(poolp, SECAlgorithmID);
171 if (mySecAlg == NULL) {
172 goto loser;
173 }
174 rv = SECOID_CopyAlgorithmID(poolp, mySecAlg, src);
175 if (rv != SECSuccess) {
176 goto loser;
177 }
178 if (mark) {
179 PORT_ArenaUnmark(poolp, mark);
180 }
181 return SECSuccess;
182
183 loser:
184 *dest = NULL;
185 if (mark) {
186 PORT_ArenaRelease(poolp, mark);
187 }
188 return SECFailure;
189 }
190
191 SECStatus
192 crmf_copy_cert_name(PLArenaPool *poolp, CERTName **dest,
193 CERTName *src)
194 {
195 CERTName *newName;
196 SECStatus rv;
197 void *mark;
198
199 mark = PORT_ArenaMark(poolp);
200 *dest = newName = PORT_ArenaZNew(poolp, CERTName);
201 if (newName == NULL) {
202 goto loser;
203 }
204
205 rv = CERT_CopyName(poolp, newName, src);
206 if (rv != SECSuccess) {
207 goto loser;
208 }
209 PORT_ArenaUnmark(poolp, mark);
210 return SECSuccess;
211 loser:
212 PORT_ArenaRelease(poolp, mark);
213 *dest = NULL;
214 return SECFailure;
215 }
216
217 static SECStatus
218 crmf_template_add_issuer (PLArenaPool *poolp, CERTName **dest,
219 CERTName* issuerName)
220 {
221 return crmf_copy_cert_name(poolp, dest, issuerName);
222 }
223
224
225 static SECStatus
226 crmf_template_add_validity (PLArenaPool *poolp, CRMFOptionalValidity **dest,
227 CRMFValidityCreationInfo *info)
228 {
229 SECStatus rv;
230 void *mark;
231 CRMFOptionalValidity *myValidity;
232
233 /*First off, let's make sure at least one of the two fields is present*/
234 if (!info || (!info->notBefore && !info->notAfter)) {
235 return SECFailure;
236 }
237 mark = PORT_ArenaMark (poolp);
238 *dest = myValidity = PORT_ArenaZNew(poolp, CRMFOptionalValidity);
239 if (myValidity == NULL) {
240 goto loser;
241 }
242
243 if (info->notBefore) {
244 rv = DER_EncodeTimeChoice (poolp, &myValidity->notBefore,
245 *info->notBefore);
246 if (rv != SECSuccess) {
247 goto loser;
248 }
249 }
250 if (info->notAfter) {
251 rv = DER_EncodeTimeChoice (poolp, &myValidity->notAfter,
252 *info->notAfter);
253 if (rv != SECSuccess) {
254 goto loser;
255 }
256 }
257 PORT_ArenaUnmark(poolp, mark);
258 return SECSuccess;
259 loser:
260 PORT_ArenaRelease(poolp, mark);
261 *dest = NULL;
262 return SECFailure;
263 }
264
265 static SECStatus
266 crmf_template_add_subject (PLArenaPool *poolp, CERTName **dest,
267 CERTName *subject)
268 {
269 return crmf_copy_cert_name(poolp, dest, subject);
270 }
271
272 SECStatus
273 crmf_template_add_public_key(PLArenaPool *poolp,
274 CERTSubjectPublicKeyInfo **dest,
275 CERTSubjectPublicKeyInfo *pubKey)
276 {
277 CERTSubjectPublicKeyInfo *spki;
278 SECStatus rv;
279
280 *dest = spki = (poolp == NULL) ?
281 PORT_ZNew(CERTSubjectPublicKeyInfo) :
282 PORT_ArenaZNew (poolp, CERTSubjectPublicKeyInfo);
283 if (spki == NULL) {
284 goto loser;
285 }
286 rv = SECKEY_CopySubjectPublicKeyInfo (poolp, spki, pubKey);
287 if (rv != SECSuccess) {
288 goto loser;
289 }
290 return SECSuccess;
291 loser:
292 if (poolp == NULL && spki != NULL) {
293 SECKEY_DestroySubjectPublicKeyInfo(spki);
294 }
295 *dest = NULL;
296 return SECFailure;
297 }
298
299 static SECStatus
300 crmf_copy_bitstring (PLArenaPool *poolp, SECItem *dest, const SECItem *src)
301 {
302 SECStatus rv;
303 SECItem byteSrc;
304
305 byteSrc = *src;
306 byteSrc.len = CRMF_BITS_TO_BYTES(byteSrc.len);
307 rv = crmf_copy_secitem(poolp, dest, &byteSrc);
308 dest->len = src->len;
309 return rv;
310 }
311
312 static SECStatus
313 crmf_template_add_issuer_uid(PLArenaPool *poolp, SECItem *dest,
314 const SECItem *issuerUID)
315 {
316 return crmf_copy_bitstring (poolp, dest, issuerUID);
317 }
318
319 static SECStatus
320 crmf_template_add_subject_uid(PLArenaPool *poolp, SECItem *dest,
321 const SECItem *subjectUID)
322 {
323 return crmf_copy_bitstring (poolp, dest, subjectUID);
324 }
325
326 static void
327 crmf_zeroize_new_extensions (CRMFCertExtension **extensions,
328 int numToZeroize)
329 {
330 PORT_Memset((void*)extensions, 0, sizeof(CERTCertExtension*)*numToZeroize);
331 }
332
333 /*
334 * The strategy for adding templates will differ from all the other
335 * attributes in the template. First, we want to allow the client
336 * of this API to set extensions more than just once. So we will
337 * need the ability grow the array of extensions. Since arenas don't
338 * give us the realloc function, we'll use the generic PORT_* functions
339 * to allocate the array of pointers *ONLY*. Then we will allocate each
340 * individual extension from the arena that comes along with the certReq
341 * structure that owns this template.
342 */
343 static SECStatus
344 crmf_template_add_extensions(PLArenaPool *poolp, CRMFCertTemplate *inTemplate,
345 CRMFCertExtCreationInfo *extensions)
346 {
347 void *mark;
348 int newSize, oldSize, i;
349 SECStatus rv;
350 CRMFCertExtension **extArray;
351 CRMFCertExtension *newExt, *currExt;
352
353 mark = PORT_ArenaMark(poolp);
354 if (inTemplate->extensions == NULL) {
355 newSize = extensions->numExtensions;
356 extArray = PORT_ZNewArray(CRMFCertExtension*,newSize+1);
357 } else {
358 newSize = inTemplate->numExtensions + extensions->numExtensions;
359 extArray = PORT_Realloc(inTemplate->extensions,
360 sizeof(CRMFCertExtension*)*(newSize+1));
361 }
362 if (extArray == NULL) {
363 goto loser;
364 }
365 oldSize = inTemplate->numExtensions;
366 inTemplate->extensions = extArray;
367 inTemplate->numExtensions = newSize;
368 for (i=oldSize; i < newSize; i++) {
369 newExt = PORT_ArenaZNew(poolp, CRMFCertExtension);
370 if (newExt == NULL) {
371 goto loser2;
372 }
373 currExt = extensions->extensions[i-oldSize];
374 rv = crmf_copy_secitem(poolp, &(newExt->id), &(currExt->id));
375 if (rv != SECSuccess) {
376 goto loser2;
377 }
378 rv = crmf_copy_secitem(poolp, &(newExt->critical),
379 &(currExt->critical));
380 if (rv != SECSuccess) {
381 goto loser2;
382 }
383 rv = crmf_copy_secitem(poolp, &(newExt->value), &(currExt->value));
384 if (rv != SECSuccess) {
385 goto loser2;
386 }
387 extArray[i] = newExt;
388 }
389 extArray[newSize] = NULL;
390 PORT_ArenaUnmark(poolp, mark);
391 return SECSuccess;
392 loser2:
393 crmf_zeroize_new_extensions (&(inTemplate->extensions[oldSize]),
394 extensions->numExtensions);
395 inTemplate->numExtensions = oldSize;
396 loser:
397 PORT_ArenaRelease(poolp, mark);
398 return SECFailure;
399 }
400
401 SECStatus
402 CRMF_CertRequestSetTemplateField(CRMFCertRequest *inCertReq,
403 CRMFCertTemplateField inTemplateField,
404 void *data)
405 {
406 CRMFCertTemplate *certTemplate;
407 PLArenaPool *poolp;
408 SECStatus rv = SECFailure;
409 void *mark;
410
411
412 if (inCertReq == NULL) {
413 return SECFailure;
414 }
415
416 certTemplate = &(inCertReq->certTemplate);
417
418 poolp = inCertReq->poolp;
419 mark = PORT_ArenaMark(poolp);
420 switch (inTemplateField) {
421 case crmfVersion:
422 rv = crmf_template_add_version(poolp,&(certTemplate->version),
423 *(long*)data);
424 break;
425 case crmfSerialNumber:
426 rv = crmf_template_add_serialnumber(poolp,
427 &(certTemplate->serialNumber),
428 *(long*)data);
429 break;
430 case crmfSigningAlg:
431 rv = crmf_template_copy_secalg (poolp, &(certTemplate->signingAlg),
432 (SECAlgorithmID*)data);
433 break;
434 case crmfIssuer:
435 rv = crmf_template_add_issuer (poolp, &(certTemplate->issuer),
436 (CERTName*)data);
437 break;
438 case crmfValidity:
439 rv = crmf_template_add_validity (poolp, &(certTemplate->validity),
440 (CRMFValidityCreationInfo*)data);
441 break;
442 case crmfSubject:
443 rv = crmf_template_add_subject (poolp, &(certTemplate->subject),
444 (CERTName*)data);
445 break;
446 case crmfPublicKey:
447 rv = crmf_template_add_public_key(poolp, &(certTemplate->publicKey),
448 (CERTSubjectPublicKeyInfo*)data);
449 break;
450 case crmfIssuerUID:
451 rv = crmf_template_add_issuer_uid(poolp, &(certTemplate->issuerUID),
452 (SECItem*)data);
453 break;
454 case crmfSubjectUID:
455 rv = crmf_template_add_subject_uid(poolp, &(certTemplate->subjectUID),
456 (SECItem*)data);
457 break;
458 case crmfExtension:
459 rv = crmf_template_add_extensions(poolp, certTemplate,
460 (CRMFCertExtCreationInfo*)data);
461 break;
462 }
463 if (rv != SECSuccess) {
464 PORT_ArenaRelease(poolp, mark);
465 } else {
466 PORT_ArenaUnmark(poolp, mark);
467 }
468 return rv;
469 }
470
471 SECStatus
472 CRMF_CertReqMsgSetCertRequest (CRMFCertReqMsg *inCertReqMsg,
473 CRMFCertRequest *inCertReq)
474 {
475 PORT_Assert (inCertReqMsg != NULL && inCertReq != NULL);
476 if (inCertReqMsg == NULL || inCertReq == NULL) {
477 return SECFailure;
478 }
479 inCertReqMsg->certReq = crmf_copy_cert_request(inCertReqMsg->poolp,
480 inCertReq);
481 return (inCertReqMsg->certReq == NULL) ? SECFailure : SECSuccess;
482 }
483
484 CRMFCertReqMsg*
485 CRMF_CreateCertReqMsg(void)
486 {
487 PLArenaPool *poolp;
488 CRMFCertReqMsg *reqMsg;
489
490 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
491 if (poolp == NULL) {
492 goto loser;
493 }
494 reqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
495 if (reqMsg == NULL) {
496 goto loser;
497 }
498 reqMsg->poolp = poolp;
499 return reqMsg;
500
501 loser:
502 if (poolp) {
503 PORT_FreeArena(poolp, PR_FALSE);
504 }
505 return NULL;
506 }
507
508 SECStatus
509 CRMF_DestroyCertReqMsg(CRMFCertReqMsg *inCertReqMsg)
510 {
511 PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->poolp != NULL);
512 if (!inCertReqMsg->isDecoded) {
513 if (inCertReqMsg->certReq->certTemplate.extensions != NULL) {
514 PORT_Free(inCertReqMsg->certReq->certTemplate.extensions);
515 }
516 if (inCertReqMsg->certReq->controls != NULL) {
517 PORT_Free(inCertReqMsg->certReq->controls);
518 }
519 }
520 PORT_FreeArena(inCertReqMsg->poolp, PR_TRUE);
521 return SECSuccess;
522 }
523
524 CRMFCertExtension*
525 crmf_create_cert_extension(PLArenaPool *poolp,
526 SECOidTag id,
527 PRBool isCritical,
528 SECItem *data)
529 {
530 CRMFCertExtension *newExt;
531 SECOidData *oidData;
532 SECStatus rv;
533
534 newExt = (poolp == NULL) ? PORT_ZNew(CRMFCertExtension) :
535 PORT_ArenaZNew(poolp, CRMFCertExtension);
536 if (newExt == NULL) {
537 goto loser;
538 }
539 oidData = SECOID_FindOIDByTag(id);
540 if (oidData == NULL ||
541 oidData->supportedExtension != SUPPORTED_CERT_EXTENSION) {
542 goto loser;
543 }
544
545 rv = SECITEM_CopyItem(poolp, &(newExt->id), &(oidData->oid));
546 if (rv != SECSuccess) {
547 goto loser;
548 }
549
550 rv = SECITEM_CopyItem(poolp, &(newExt->value), data);
551 if (rv != SECSuccess) {
552 goto loser;
553 }
554
555 if (isCritical) {
556 newExt->critical.data = (poolp == NULL) ?
557 PORT_New(unsigned char) :
558 PORT_ArenaNew(poolp, unsigned char);
559 if (newExt->critical.data == NULL) {
560 goto loser;
561 }
562 newExt->critical.data[0] = hexTrue;
563 newExt->critical.len = 1;
564 }
565 return newExt;
566 loser:
567 if (newExt != NULL && poolp == NULL) {
568 CRMF_DestroyCertExtension(newExt);
569 }
570 return NULL;
571 }
572
573 CRMFCertExtension *
574 CRMF_CreateCertExtension(SECOidTag id,
575 PRBool isCritical,
576 SECItem *data)
577 {
578 return crmf_create_cert_extension(NULL, id, isCritical, data);
579 }
580
581 static SECStatus
582 crmf_destroy_cert_extension(CRMFCertExtension *inExtension, PRBool freeit)
583 {
584 if (inExtension != NULL) {
585 SECITEM_FreeItem (&(inExtension->id), PR_FALSE);
586 SECITEM_FreeItem (&(inExtension->value), PR_FALSE);
587 SECITEM_FreeItem (&(inExtension->critical), PR_FALSE);
588 if (freeit) {
589 PORT_Free(inExtension);
590 }
591 }
592 return SECSuccess;
593 }
594
595 SECStatus
596 CRMF_DestroyCertExtension(CRMFCertExtension *inExtension)
597 {
598 return crmf_destroy_cert_extension(inExtension, PR_TRUE);
599 }
600
601 SECStatus
602 CRMF_DestroyCertReqMessages(CRMFCertReqMessages *inCertReqMsgs)
603 {
604 PORT_Assert (inCertReqMsgs != NULL);
605 if (inCertReqMsgs != NULL) {
606 PORT_FreeArena(inCertReqMsgs->poolp, PR_TRUE);
607 }
608 return SECSuccess;
609 }
610
611 static PRBool
612 crmf_item_has_data(SECItem *item)
613 {
614 if (item != NULL && item->data != NULL) {
615 return PR_TRUE;
616 }
617 return PR_FALSE;
618 }
619
620 PRBool
621 CRMF_CertRequestIsFieldPresent(CRMFCertRequest *inCertReq,
622 CRMFCertTemplateField inTemplateField)
623 {
624 PRBool retVal;
625 CRMFCertTemplate *certTemplate;
626
627 PORT_Assert(inCertReq != NULL);
628 if (inCertReq == NULL) {
629 /* This is probably some kind of error, but this is
630 * the safest return value for this function.
631 */
632 return PR_FALSE;
633 }
634 certTemplate = &inCertReq->certTemplate;
635 switch (inTemplateField) {
636 case crmfVersion:
637 retVal = crmf_item_has_data(&certTemplate->version);
638 break;
639 case crmfSerialNumber:
640 retVal = crmf_item_has_data(&certTemplate->serialNumber);
641 break;
642 case crmfSigningAlg:
643 retVal = IS_NOT_NULL(certTemplate->signingAlg);
644 break;
645 case crmfIssuer:
646 retVal = IS_NOT_NULL(certTemplate->issuer);
647 break;
648 case crmfValidity:
649 retVal = IS_NOT_NULL(certTemplate->validity);
650 break;
651 case crmfSubject:
652 retVal = IS_NOT_NULL(certTemplate->subject);
653 break;
654 case crmfPublicKey:
655 retVal = IS_NOT_NULL(certTemplate->publicKey);
656 break;
657 case crmfIssuerUID:
658 retVal = crmf_item_has_data(&certTemplate->issuerUID);
659 break;
660 case crmfSubjectUID:
661 retVal = crmf_item_has_data(&certTemplate->subjectUID);
662 break;
663 case crmfExtension:
664 retVal = IS_NOT_NULL(certTemplate->extensions);
665 break;
666 default:
667 retVal = PR_FALSE;
668 }
669 return retVal;
670 }

mercurial