OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 | |
5 /* | |
6 * X.509 v3 Basic Constraints Extension | |
7 */ | |
8 | |
9 #include "prtypes.h" | |
10 #include <limits.h> /* for LONG_MAX */ | |
11 #include "seccomon.h" | |
12 #include "secdert.h" | |
13 #include "secoidt.h" | |
14 #include "secasn1t.h" | |
15 #include "secasn1.h" | |
16 #include "certt.h" | |
17 #include "secder.h" | |
18 #include "prprf.h" | |
19 #include "secerr.h" | |
20 | |
21 typedef struct EncodedContext { | |
22 SECItem isCA; | |
23 SECItem pathLenConstraint; | |
24 SECItem encodedValue; | |
25 PLArenaPool *arena; | |
26 } EncodedContext; | |
27 | |
28 static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = { | |
29 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(EncodedContext) }, | |
30 { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ | |
31 offsetof(EncodedContext, isCA) }, | |
32 { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, | |
33 offsetof(EncodedContext, pathLenConstraint) }, | |
34 { 0 } | |
35 }; | |
36 | |
37 static unsigned char hexTrue = 0xff; | |
38 static unsigned char hexFalse = 0x00; | |
39 | |
40 #define GEN_BREAK(status) \ | |
41 rv = status; \ | |
42 break; | |
43 | |
44 SECStatus | |
45 CERT_EncodeBasicConstraintValue(PLArenaPool *arena, CERTBasicConstraints *value, | |
46 SECItem *encodedValue) | |
47 { | |
48 EncodedContext encodeContext; | |
49 PLArenaPool *our_pool = NULL; | |
50 SECStatus rv = SECSuccess; | |
51 | |
52 do { | |
53 PORT_Memset(&encodeContext, 0, sizeof(encodeContext)); | |
54 if (!value->isCA && value->pathLenConstraint >= 0) { | |
55 PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); | |
56 GEN_BREAK(SECFailure); | |
57 } | |
58 | |
59 encodeContext.arena = arena; | |
60 if (value->isCA == PR_TRUE) { | |
61 encodeContext.isCA.data = &hexTrue; | |
62 encodeContext.isCA.len = 1; | |
63 } | |
64 | |
65 /* If the pathLenConstraint is less than 0, then it should be | |
66 * omitted from the encoding. | |
67 */ | |
68 if (value->isCA && value->pathLenConstraint >= 0) { | |
69 our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); | |
70 if (our_pool == NULL) { | |
71 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
72 GEN_BREAK(SECFailure); | |
73 } | |
74 if (SEC_ASN1EncodeUnsignedInteger( | |
75 our_pool, &encodeContext.pathLenConstraint, | |
76 (unsigned long)value->pathLenConstraint) == NULL) { | |
77 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
78 GEN_BREAK(SECFailure); | |
79 } | |
80 } | |
81 if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext, | |
82 CERTBasicConstraintsTemplate) == NULL) { | |
83 GEN_BREAK(SECFailure); | |
84 } | |
85 } while (0); | |
86 if (our_pool) | |
87 PORT_FreeArena(our_pool, PR_FALSE); | |
88 return (rv); | |
89 } | |
90 | |
91 SECStatus | |
92 CERT_DecodeBasicConstraintValue(CERTBasicConstraints *value, | |
93 const SECItem *encodedValue) | |
94 { | |
95 EncodedContext decodeContext; | |
96 PLArenaPool *our_pool; | |
97 SECStatus rv = SECSuccess; | |
98 | |
99 do { | |
100 PORT_Memset(&decodeContext, 0, sizeof(decodeContext)); | |
101 /* initialize the value just in case we got "0x30 00", or when the | |
102 pathLenConstraint is omitted. | |
103 */ | |
104 decodeContext.isCA.data = &hexFalse; | |
105 decodeContext.isCA.len = 1; | |
106 | |
107 our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); | |
108 if (our_pool == NULL) { | |
109 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
110 GEN_BREAK(SECFailure); | |
111 } | |
112 | |
113 rv = SEC_QuickDERDecodeItem(our_pool, &decodeContext, | |
114 CERTBasicConstraintsTemplate, encodedValue); | |
115 if (rv == SECFailure) | |
116 break; | |
117 | |
118 value->isCA = decodeContext.isCA.data | |
119 ? (PRBool)(decodeContext.isCA.data[0] != 0) | |
120 : PR_FALSE; | |
121 if (decodeContext.pathLenConstraint.data == NULL) { | |
122 /* if the pathLenConstraint is not encoded, and the current setting | |
123 is CA, then the pathLenConstraint should be set to a negative | |
124 number | |
125 for unlimited certificate path. | |
126 */ | |
127 if (value->isCA) | |
128 value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; | |
129 } else if (value->isCA) { | |
130 long len = DER_GetInteger(&decodeContext.pathLenConstraint); | |
131 if (len < 0 || len == LONG_MAX) { | |
132 PORT_SetError(SEC_ERROR_BAD_DER); | |
133 GEN_BREAK(SECFailure); | |
134 } | |
135 value->pathLenConstraint = len; | |
136 } else { | |
137 /* here we get an error where the subject is not a CA, but | |
138 the pathLenConstraint is set */ | |
139 PORT_SetError(SEC_ERROR_BAD_DER); | |
140 GEN_BREAK(SECFailure); | |
141 break; | |
142 } | |
143 | |
144 } while (0); | |
145 PORT_FreeArena(our_pool, PR_FALSE); | |
146 return (rv); | |
147 } | |
OLD | NEW |