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
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.
22 * John Gardiner Myers <jgmyers@speakeasy.net>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 #include "secder.h" /* XXX remove this when remove the DERTemplates */
47 static const SEC_ASN1Template cert_AVATemplate
[] = {
49 0, NULL
, sizeof(CERTAVA
) },
51 offsetof(CERTAVA
,type
), },
53 offsetof(CERTAVA
,value
), },
57 const SEC_ASN1Template CERT_RDNTemplate
[] = {
59 offsetof(CERTRDN
,avas
), cert_AVATemplate
, sizeof(CERTRDN
) }
64 CountArray(void **array
)
76 AddToArray(PRArenaPool
*arena
, void **array
, void *element
)
81 /* Count up number of slots already in use in the array */
91 array
= (void**) PORT_ArenaGrow(arena
, array
,
92 (count
+ 1) * sizeof(void *),
93 (count
+ 2) * sizeof(void *));
95 array
= (void**) PORT_ArenaAlloc(arena
, (count
+ 2) * sizeof(void *));
98 array
[count
] = element
;
106 CERT_GetAVATag(CERTAVA
*ava
)
109 if (!ava
->type
.data
) return (SECOidTag
)-1;
111 oid
= SECOID_FindOID(&ava
->type
);
116 return (SECOidTag
)-1;
120 SetupAVAType(PRArenaPool
*arena
, SECOidTag type
, SECItem
*it
, unsigned *maxLenp
)
128 oidrec
= SECOID_FindOIDByTag(type
);
132 oid
= oidrec
->oid
.data
;
133 oidLen
= oidrec
->oid
.len
;
135 maxLen
= cert_AVAOidTagToMaxLen(type
);
137 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
141 it
->data
= cp
= (unsigned char*) PORT_ArenaAlloc(arena
, oidLen
);
146 PORT_Memcpy(cp
, oid
, oidLen
);
147 *maxLenp
= (unsigned)maxLen
;
152 SetupAVAValue(PRArenaPool
*arena
, int valueType
, char *value
, SECItem
*it
,
155 unsigned valueLen
, valueLenLen
, total
;
156 unsigned ucs4Len
= 0, ucs4MaxLen
;
157 unsigned char *cp
, *ucs4Val
;
160 case SEC_ASN1_PRINTABLE_STRING
:
161 case SEC_ASN1_IA5_STRING
:
162 case SEC_ASN1_T61_STRING
:
163 case SEC_ASN1_UTF8_STRING
: /* no conversion required */
164 valueLen
= PORT_Strlen(value
);
166 case SEC_ASN1_UNIVERSAL_STRING
:
167 valueLen
= PORT_Strlen(value
);
168 ucs4MaxLen
= valueLen
* 6;
169 ucs4Val
= (unsigned char *)PORT_ArenaZAlloc(arena
, ucs4MaxLen
);
170 if(!ucs4Val
|| !PORT_UCS4_UTF8Conversion(PR_TRUE
,
171 (unsigned char *)value
, valueLen
,
172 ucs4Val
, ucs4MaxLen
, &ucs4Len
)) {
173 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
176 value
= (char *)ucs4Val
;
181 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
185 if (valueLen
> maxLen
) {
186 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
190 valueLenLen
= DER_LengthLength(valueLen
);
191 total
= 1 + valueLenLen
+ valueLen
;
192 it
->data
= cp
= (unsigned char*) PORT_ArenaAlloc(arena
, total
);
197 cp
= (unsigned char*) DER_StoreHeader(cp
, valueType
, valueLen
);
198 PORT_Memcpy(cp
, value
, valueLen
);
203 CERT_CreateAVAFromRaw(PRArenaPool
*pool
, const SECItem
* OID
,
204 const SECItem
* value
)
209 ava
= PORT_ArenaZNew(pool
, CERTAVA
);
211 rv
= SECITEM_CopyItem(pool
, &ava
->type
, OID
);
215 rv
= SECITEM_CopyItem(pool
, &ava
->value
, value
);
223 CERT_CreateAVA(PRArenaPool
*arena
, SECOidTag kind
, int valueType
, char *value
)
229 ava
= (CERTAVA
*) PORT_ArenaZAlloc(arena
, sizeof(CERTAVA
));
231 rv
= SetupAVAType(arena
, kind
, &ava
->type
, &maxLen
);
233 /* Illegal AVA type */
236 rv
= SetupAVAValue(arena
, valueType
, value
, &ava
->value
, maxLen
);
238 /* Illegal value type */
246 CERT_CopyAVA(PRArenaPool
*arena
, CERTAVA
*from
)
251 ava
= (CERTAVA
*) PORT_ArenaZAlloc(arena
, sizeof(CERTAVA
));
253 rv
= SECITEM_CopyItem(arena
, &ava
->type
, &from
->type
);
255 rv
= SECITEM_CopyItem(arena
, &ava
->value
, &from
->value
);
264 /************************************************************************/
265 /* XXX This template needs to go away in favor of the new SEC_ASN1 version. */
266 static const SEC_ASN1Template cert_RDNTemplate
[] = {
268 offsetof(CERTRDN
,avas
), cert_AVATemplate
, sizeof(CERTRDN
) }
273 CERT_CreateRDN(PRArenaPool
*arena
, CERTAVA
*ava0
, ...)
281 rdn
= (CERTRDN
*) PORT_ArenaAlloc(arena
, sizeof(CERTRDN
));
283 /* Count number of avas going into the rdn */
288 while ((ava
= va_arg(ap
, CERTAVA
*)) != 0) {
294 /* Now fill in the pointers */
296 (CERTAVA
**) PORT_ArenaAlloc( arena
, (count
+ 1)*sizeof(CERTAVA
*));
303 while ((ava
= va_arg(ap
, CERTAVA
*)) != 0) {
314 CERT_AddAVA(PRArenaPool
*arena
, CERTRDN
*rdn
, CERTAVA
*ava
)
316 rdn
->avas
= (CERTAVA
**) AddToArray(arena
, (void**) rdn
->avas
, ava
);
317 return rdn
->avas
? SECSuccess
: SECFailure
;
321 CERT_CopyRDN(PRArenaPool
*arena
, CERTRDN
*to
, CERTRDN
*from
)
323 CERTAVA
**avas
, *fava
, *tava
;
324 SECStatus rv
= SECSuccess
;
326 /* Copy each ava from from */
329 if (avas
[0] == NULL
) {
330 rv
= CERT_AddAVA(arena
, to
, NULL
);
333 while ((fava
= *avas
++) != 0) {
334 tava
= CERT_CopyAVA(arena
, fava
);
339 rv
= CERT_AddAVA(arena
, to
, tava
);
340 if (rv
!= SECSuccess
)
347 /************************************************************************/
349 const SEC_ASN1Template CERT_NameTemplate
[] = {
350 { SEC_ASN1_SEQUENCE_OF
,
351 offsetof(CERTName
,rdns
), CERT_RDNTemplate
, sizeof(CERTName
) }
354 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate
)
357 CERT_CreateName(CERTRDN
*rdn0
, ...)
366 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
371 name
= (CERTName
*) PORT_ArenaAlloc(arena
, sizeof(CERTName
));
375 /* Count number of RDNs going into the Name */
381 while ((rdn
= va_arg(ap
, CERTRDN
*)) != 0) {
387 /* Allocate space (including space for terminal null ptr) */
389 (CERTRDN
**) PORT_ArenaAlloc(arena
, (count
+ 1) * sizeof(CERTRDN
*));
394 /* Now fill in the pointers */
398 while ((rdn
= va_arg(ap
, CERTRDN
*)) != 0) {
404 /* null terminate the list */
410 PORT_FreeArena(arena
, PR_FALSE
);
415 CERT_DestroyName(CERTName
*name
)
419 PRArenaPool
*arena
= name
->arena
;
422 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
427 CERT_AddRDN(CERTName
*name
, CERTRDN
*rdn
)
429 name
->rdns
= (CERTRDN
**) AddToArray(name
->arena
, (void**) name
->rdns
, rdn
);
430 return name
->rdns
? SECSuccess
: SECFailure
;
434 CERT_CopyName(PRArenaPool
*arena
, CERTName
*to
, CERTName
*from
)
436 CERTRDN
**rdns
, *frdn
, *trdn
;
437 SECStatus rv
= SECSuccess
;
440 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
444 CERT_DestroyName(to
);
447 /* Copy each rdn from from */
450 if (rdns
[0] == NULL
) {
451 rv
= CERT_AddRDN(to
, NULL
);
454 while ((frdn
= *rdns
++) != NULL
) {
455 trdn
= CERT_CreateRDN(arena
, NULL
);
460 rv
= CERT_CopyRDN(arena
, trdn
, frdn
);
461 if (rv
!= SECSuccess
)
463 rv
= CERT_AddRDN(to
, trdn
);
464 if (rv
!= SECSuccess
)
471 /************************************************************************/
474 canonicalize(SECItem
* foo
)
476 int ch
, lastch
, len
, src
, dest
;
478 /* strip trailing whitespace. */
480 while (len
> 0 && ((ch
= foo
->data
[len
- 1]) == ' ' ||
481 ch
== '\t' || ch
== '\r' || ch
== '\n')) {
486 /* strip leading whitespace. */
487 while (src
< len
&& ((ch
= foo
->data
[src
]) == ' ' ||
488 ch
== '\t' || ch
== '\r' || ch
== '\n')) {
491 dest
= 0; lastch
= ' ';
493 ch
= foo
->data
[src
++];
494 if (ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n') {
498 } else if (ch
>= 'A' && ch
<= 'Z') {
499 ch
|= 0x20; /* downshift */
501 foo
->data
[dest
++] = lastch
= ch
;
506 /* SECItems a and b contain DER-encoded printable strings. */
508 CERT_CompareDERPrintableStrings(const SECItem
*a
, const SECItem
*b
)
510 SECComparison rv
= SECLessThan
;
511 SECItem
* aVal
= CERT_DecodeAVAValue(a
);
512 SECItem
* bVal
= CERT_DecodeAVAValue(b
);
514 if (aVal
&& aVal
->len
&& aVal
->data
&&
515 bVal
&& bVal
->len
&& bVal
->data
) {
518 rv
= SECITEM_CompareItem(aVal
, bVal
);
520 SECITEM_FreeItem(aVal
, PR_TRUE
);
521 SECITEM_FreeItem(bVal
, PR_TRUE
);
526 CERT_CompareAVA(const CERTAVA
*a
, const CERTAVA
*b
)
530 rv
= SECITEM_CompareItem(&a
->type
, &b
->type
);
532 return rv
; /* Attribute types don't match. */
533 /* Let's be optimistic. Maybe the values will just compare equal. */
534 rv
= SECITEM_CompareItem(&a
->value
, &b
->value
);
536 return rv
; /* values compared exactly. */
537 if (a
->value
.len
&& a
->value
.data
&& b
->value
.len
&& b
->value
.data
) {
538 /* Here, the values did not match.
539 ** If the values had different encodings, convert them to the same
540 ** encoding and compare that way.
542 if (a
->value
.data
[0] != b
->value
.data
[0]) {
543 /* encodings differ. Convert both to UTF-8 and compare. */
544 SECItem
* aVal
= CERT_DecodeAVAValue(&a
->value
);
545 SECItem
* bVal
= CERT_DecodeAVAValue(&b
->value
);
546 if (aVal
&& aVal
->len
&& aVal
->data
&&
547 bVal
&& bVal
->len
&& bVal
->data
) {
548 rv
= SECITEM_CompareItem(aVal
, bVal
);
550 SECITEM_FreeItem(aVal
, PR_TRUE
);
551 SECITEM_FreeItem(bVal
, PR_TRUE
);
552 } else if (a
->value
.data
[0] == 0x13) { /* both are printable strings. */
553 /* printable strings */
554 rv
= CERT_CompareDERPrintableStrings(&a
->value
, &b
->value
);
561 CERT_CompareRDN(CERTRDN
*a
, CERTRDN
*b
)
563 CERTAVA
**aavas
, *aava
;
564 CERTAVA
**bavas
, *bava
;
566 SECComparison rv
= SECEqual
;
572 ** Make sure array of ava's are the same length. If not, then we are
575 ac
= CountArray((void**) aavas
);
576 bc
= CountArray((void**) bavas
);
577 if (ac
< bc
) return SECLessThan
;
578 if (ac
> bc
) return SECGreaterThan
;
580 while (NULL
!= (aava
= *aavas
++)) {
581 for (bavas
= b
->avas
; bava
= *bavas
++; ) {
582 rv
= SECITEM_CompareItem(&aava
->type
, &bava
->type
);
583 if (SECEqual
== rv
) {
584 rv
= CERT_CompareAVA(aava
, bava
);
590 if (!bava
) /* didn't find a match */
591 return SECGreaterThan
;
597 CERT_CompareName(CERTName
*a
, CERTName
*b
)
599 CERTRDN
**ardns
, *ardn
;
600 CERTRDN
**brdns
, *brdn
;
602 SECComparison rv
= SECEqual
;
608 ** Make sure array of rdn's are the same length. If not, then we are
611 ac
= CountArray((void**) ardns
);
612 bc
= CountArray((void**) brdns
);
613 if (ac
< bc
) return SECLessThan
;
614 if (ac
> bc
) return SECGreaterThan
;
622 rv
= CERT_CompareRDN(ardn
, brdn
);
628 /* Moved from certhtml.c */
630 CERT_DecodeAVAValue(const SECItem
*derAVAValue
)
633 const SEC_ASN1Template
*theTemplate
= NULL
;
634 enum { conv_none
, conv_ucs4
, conv_ucs2
, conv_iso88591
} convert
= conv_none
;
635 SECItem avaValue
= {siBuffer
, 0};
636 PLArenaPool
*newarena
= NULL
;
638 if (!derAVAValue
|| !derAVAValue
->len
|| !derAVAValue
->data
) {
639 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
643 switch(derAVAValue
->data
[0]) {
644 case SEC_ASN1_UNIVERSAL_STRING
:
646 theTemplate
= SEC_ASN1_GET(SEC_UniversalStringTemplate
);
648 case SEC_ASN1_IA5_STRING
:
649 theTemplate
= SEC_ASN1_GET(SEC_IA5StringTemplate
);
651 case SEC_ASN1_PRINTABLE_STRING
:
652 theTemplate
= SEC_ASN1_GET(SEC_PrintableStringTemplate
);
654 case SEC_ASN1_T61_STRING
:
656 * Per common practice, we're not decoding actual T.61, but instead
657 * treating T61-labeled strings as containing ISO-8859-1.
659 convert
= conv_iso88591
;
660 theTemplate
= SEC_ASN1_GET(SEC_T61StringTemplate
);
662 case SEC_ASN1_BMP_STRING
:
664 theTemplate
= SEC_ASN1_GET(SEC_BMPStringTemplate
);
666 case SEC_ASN1_UTF8_STRING
:
667 /* No conversion needed ! */
668 theTemplate
= SEC_ASN1_GET(SEC_UTF8StringTemplate
);
671 PORT_SetError(SEC_ERROR_INVALID_AVA
);
675 PORT_Memset(&avaValue
, 0, sizeof(SECItem
));
676 newarena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
680 if(SEC_QuickDERDecodeItem(newarena
, &avaValue
, theTemplate
, derAVAValue
)
682 PORT_FreeArena(newarena
, PR_FALSE
);
686 if (convert
!= conv_none
) {
687 unsigned int utf8ValLen
= avaValue
.len
* 3;
688 unsigned char *utf8Val
= (unsigned char*)
689 PORT_ArenaZAlloc(newarena
, utf8ValLen
);
693 if(avaValue
.len
% 4 != 0 ||
694 !PORT_UCS4_UTF8Conversion(PR_FALSE
, avaValue
.data
, avaValue
.len
,
695 utf8Val
, utf8ValLen
, &utf8ValLen
)) {
696 PORT_FreeArena(newarena
, PR_FALSE
);
697 PORT_SetError(SEC_ERROR_INVALID_AVA
);
702 if(avaValue
.len
% 2 != 0 ||
703 !PORT_UCS2_UTF8Conversion(PR_FALSE
, avaValue
.data
, avaValue
.len
,
704 utf8Val
, utf8ValLen
, &utf8ValLen
)) {
705 PORT_FreeArena(newarena
, PR_FALSE
);
706 PORT_SetError(SEC_ERROR_INVALID_AVA
);
711 if(!PORT_ISO88591_UTF8Conversion(avaValue
.data
, avaValue
.len
,
712 utf8Val
, utf8ValLen
, &utf8ValLen
)) {
713 PORT_FreeArena(newarena
, PR_FALSE
);
714 PORT_SetError(SEC_ERROR_INVALID_AVA
);
719 PORT_Assert(0); /* not reached */
723 avaValue
.data
= utf8Val
;
724 avaValue
.len
= utf8ValLen
;
727 retItem
= SECITEM_DupItem(&avaValue
);
728 PORT_FreeArena(newarena
, PR_FALSE
);