|
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, |
|
30 0, NULL, sizeof(EncodedContext) }, |
|
31 { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ |
|
32 offsetof(EncodedContext,isCA)}, |
|
33 { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, |
|
34 offsetof(EncodedContext,pathLenConstraint) }, |
|
35 { 0, } |
|
36 }; |
|
37 |
|
38 static unsigned char hexTrue = 0xff; |
|
39 static unsigned char hexFalse = 0x00; |
|
40 |
|
41 #define GEN_BREAK(status) rv = status; break; |
|
42 |
|
43 SECStatus CERT_EncodeBasicConstraintValue |
|
44 (PLArenaPool *arena, CERTBasicConstraints *value, SECItem *encodedValue) |
|
45 { |
|
46 EncodedContext encodeContext; |
|
47 PLArenaPool *our_pool = NULL; |
|
48 SECStatus rv = SECSuccess; |
|
49 |
|
50 do { |
|
51 PORT_Memset (&encodeContext, 0, sizeof (encodeContext)); |
|
52 if (!value->isCA && value->pathLenConstraint >= 0) { |
|
53 PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
54 GEN_BREAK (SECFailure); |
|
55 } |
|
56 |
|
57 encodeContext.arena = arena; |
|
58 if (value->isCA == PR_TRUE) { |
|
59 encodeContext.isCA.data = &hexTrue ; |
|
60 encodeContext.isCA.len = 1; |
|
61 } |
|
62 |
|
63 /* If the pathLenConstraint is less than 0, then it should be |
|
64 * omitted from the encoding. |
|
65 */ |
|
66 if (value->isCA && value->pathLenConstraint >= 0) { |
|
67 our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
68 if (our_pool == NULL) { |
|
69 PORT_SetError (SEC_ERROR_NO_MEMORY); |
|
70 GEN_BREAK (SECFailure); |
|
71 } |
|
72 if (SEC_ASN1EncodeUnsignedInteger |
|
73 (our_pool, &encodeContext.pathLenConstraint, |
|
74 (unsigned long)value->pathLenConstraint) == NULL) { |
|
75 PORT_SetError (SEC_ERROR_NO_MEMORY); |
|
76 GEN_BREAK (SECFailure); |
|
77 } |
|
78 } |
|
79 if (SEC_ASN1EncodeItem (arena, encodedValue, &encodeContext, |
|
80 CERTBasicConstraintsTemplate) == NULL) { |
|
81 GEN_BREAK (SECFailure); |
|
82 } |
|
83 } while (0); |
|
84 if (our_pool) |
|
85 PORT_FreeArena (our_pool, PR_FALSE); |
|
86 return(rv); |
|
87 |
|
88 } |
|
89 |
|
90 SECStatus CERT_DecodeBasicConstraintValue |
|
91 (CERTBasicConstraints *value, const SECItem *encodedValue) |
|
92 { |
|
93 EncodedContext decodeContext; |
|
94 PLArenaPool *our_pool; |
|
95 SECStatus rv = SECSuccess; |
|
96 |
|
97 do { |
|
98 PORT_Memset (&decodeContext, 0, sizeof (decodeContext)); |
|
99 /* initialize the value just in case we got "0x30 00", or when the |
|
100 pathLenConstraint is omitted. |
|
101 */ |
|
102 decodeContext.isCA.data =&hexFalse; |
|
103 decodeContext.isCA.len = 1; |
|
104 |
|
105 our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
106 if (our_pool == NULL) { |
|
107 PORT_SetError (SEC_ERROR_NO_MEMORY); |
|
108 GEN_BREAK (SECFailure); |
|
109 } |
|
110 |
|
111 rv = SEC_QuickDERDecodeItem |
|
112 (our_pool, &decodeContext, CERTBasicConstraintsTemplate, encodedValue); |
|
113 if (rv == SECFailure) |
|
114 break; |
|
115 |
|
116 value->isCA = decodeContext.isCA.data |
|
117 ? (PRBool)(decodeContext.isCA.data[0] != 0) |
|
118 : PR_FALSE; |
|
119 if (decodeContext.pathLenConstraint.data == NULL) { |
|
120 /* if the pathLenConstraint is not encoded, and the current setting |
|
121 is CA, then the pathLenConstraint should be set to a negative number |
|
122 for unlimited certificate path. |
|
123 */ |
|
124 if (value->isCA) |
|
125 value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; |
|
126 } else if (value->isCA) { |
|
127 long len = DER_GetInteger (&decodeContext.pathLenConstraint); |
|
128 if (len < 0 || len == LONG_MAX) { |
|
129 PORT_SetError (SEC_ERROR_BAD_DER); |
|
130 GEN_BREAK (SECFailure); |
|
131 } |
|
132 value->pathLenConstraint = len; |
|
133 } else { |
|
134 /* here we get an error where the subject is not a CA, but |
|
135 the pathLenConstraint is set */ |
|
136 PORT_SetError (SEC_ERROR_BAD_DER); |
|
137 GEN_BREAK (SECFailure); |
|
138 break; |
|
139 } |
|
140 |
|
141 } while (0); |
|
142 PORT_FreeArena (our_pool, PR_FALSE); |
|
143 return (rv); |
|
144 |
|
145 } |