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 Extension Encoding
7  */
8 
9 #include "prtypes.h"
10 #include "seccomon.h"
11 #include "secdert.h"
12 #include "secoidt.h"
13 #include "secasn1t.h"
14 #include "secasn1.h"
15 #include "cert.h"
16 #include "secder.h"
17 #include "prprf.h"
18 #include "xconst.h"
19 #include "genname.h"
20 #include "secasn1.h"
21 #include "secerr.h"
22 
23 static const SEC_ASN1Template CERTSubjectKeyIDTemplate[] = {
24     { SEC_ASN1_OCTET_STRING }
25 };
26 
27 static const SEC_ASN1Template CERTIA5TypeTemplate[] = {
28     { SEC_ASN1_IA5_STRING }
29 };
30 
31 SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate)
32 
33 static const SEC_ASN1Template CERTPrivateKeyUsagePeriodTemplate[] = {
34     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPrivKeyUsagePeriod) },
35     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
36       offsetof(CERTPrivKeyUsagePeriod, notBefore),
37       SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
38     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
39       offsetof(CERTPrivKeyUsagePeriod, notAfter),
40       SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
41     { 0 }
42 };
43 
44 const SEC_ASN1Template CERTAltNameTemplate[] = {
45     { SEC_ASN1_CONSTRUCTED, offsetof(CERTAltNameEncodedContext, encodedGenName),
46       CERT_GeneralNamesTemplate }
47 };
48 
49 const SEC_ASN1Template CERTAuthInfoAccessItemTemplate[] = {
50     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAuthInfoAccess) },
51     { SEC_ASN1_OBJECT_ID, offsetof(CERTAuthInfoAccess, method) },
52     { SEC_ASN1_ANY, offsetof(CERTAuthInfoAccess, derLocation) },
53     { 0 }
54 };
55 
56 const SEC_ASN1Template CERTAuthInfoAccessTemplate[] = {
57     { SEC_ASN1_SEQUENCE_OF, 0, CERTAuthInfoAccessItemTemplate }
58 };
59 
60 SECStatus
CERT_EncodeSubjectKeyID(PLArenaPool * arena,const SECItem * srcString,SECItem * encodedValue)61 CERT_EncodeSubjectKeyID(PLArenaPool *arena, const SECItem *srcString,
62                         SECItem *encodedValue)
63 {
64     SECStatus rv = SECSuccess;
65 
66     if (!srcString) {
67         PORT_SetError(SEC_ERROR_INVALID_ARGS);
68         return SECFailure;
69     }
70     if (SEC_ASN1EncodeItem(arena, encodedValue, srcString,
71                            CERTSubjectKeyIDTemplate) == NULL) {
72         rv = SECFailure;
73     }
74 
75     return (rv);
76 }
77 
78 SECStatus
CERT_EncodePrivateKeyUsagePeriod(PLArenaPool * arena,CERTPrivKeyUsagePeriod * pkup,SECItem * encodedValue)79 CERT_EncodePrivateKeyUsagePeriod(PLArenaPool *arena,
80                                  CERTPrivKeyUsagePeriod *pkup,
81                                  SECItem *encodedValue)
82 {
83     SECStatus rv = SECSuccess;
84 
85     if (SEC_ASN1EncodeItem(arena, encodedValue, pkup,
86                            CERTPrivateKeyUsagePeriodTemplate) == NULL) {
87         rv = SECFailure;
88     }
89     return (rv);
90 }
91 
92 CERTPrivKeyUsagePeriod *
CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool * arena,SECItem * extnValue)93 CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue)
94 {
95     SECStatus rv;
96     CERTPrivKeyUsagePeriod *pPeriod;
97     SECItem newExtnValue;
98 
99     /* allocate the certificate policies structure */
100     pPeriod = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod);
101     if (pPeriod == NULL) {
102         goto loser;
103     }
104 
105     pPeriod->arena = arena;
106 
107     /* copy the DER into the arena, since Quick DER returns data that points
108        into the DER input, which may get freed by the caller */
109     rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
110     if (rv != SECSuccess) {
111         goto loser;
112     }
113 
114     rv = SEC_QuickDERDecodeItem(
115         arena, pPeriod, CERTPrivateKeyUsagePeriodTemplate, &newExtnValue);
116     if (rv != SECSuccess) {
117         goto loser;
118     }
119     return pPeriod;
120 
121 loser:
122     return NULL;
123 }
124 
125 SECStatus
CERT_EncodeIA5TypeExtension(PLArenaPool * arena,char * value,SECItem * encodedValue)126 CERT_EncodeIA5TypeExtension(PLArenaPool *arena, char *value,
127                             SECItem *encodedValue)
128 {
129     SECItem encodeContext;
130     SECStatus rv = SECSuccess;
131 
132     PORT_Memset(&encodeContext, 0, sizeof(encodeContext));
133 
134     if (value != NULL) {
135         encodeContext.data = (unsigned char *)value;
136         encodeContext.len = strlen(value);
137     }
138     if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext,
139                            CERTIA5TypeTemplate) == NULL) {
140         rv = SECFailure;
141     }
142 
143     return (rv);
144 }
145 
146 SECStatus
CERT_EncodeAltNameExtension(PLArenaPool * arena,CERTGeneralName * value,SECItem * encodedValue)147 CERT_EncodeAltNameExtension(PLArenaPool *arena, CERTGeneralName *value,
148                             SECItem *encodedValue)
149 {
150     SECItem **encodedGenName;
151     SECStatus rv = SECSuccess;
152 
153     encodedGenName = cert_EncodeGeneralNames(arena, value);
154     if (SEC_ASN1EncodeItem(arena, encodedValue, &encodedGenName,
155                            CERT_GeneralNamesTemplate) == NULL) {
156         rv = SECFailure;
157     }
158 
159     return rv;
160 }
161 
162 CERTGeneralName *
CERT_DecodeAltNameExtension(PLArenaPool * reqArena,SECItem * EncodedAltName)163 CERT_DecodeAltNameExtension(PLArenaPool *reqArena, SECItem *EncodedAltName)
164 {
165     SECStatus rv = SECSuccess;
166     CERTAltNameEncodedContext encodedContext;
167     SECItem *newEncodedAltName;
168 
169     if (!reqArena) {
170         PORT_SetError(SEC_ERROR_INVALID_ARGS);
171         return NULL;
172     }
173 
174     newEncodedAltName = SECITEM_ArenaDupItem(reqArena, EncodedAltName);
175     if (!newEncodedAltName) {
176         return NULL;
177     }
178 
179     encodedContext.encodedGenName = NULL;
180     PORT_Memset(&encodedContext, 0, sizeof(CERTAltNameEncodedContext));
181     rv = SEC_QuickDERDecodeItem(reqArena, &encodedContext,
182                                 CERT_GeneralNamesTemplate, newEncodedAltName);
183     if (rv == SECFailure) {
184         goto loser;
185     }
186     if (encodedContext.encodedGenName && encodedContext.encodedGenName[0])
187         return cert_DecodeGeneralNames(reqArena, encodedContext.encodedGenName);
188     /* Extension contained an empty GeneralNames sequence */
189     /* Treat as extension not found */
190     PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
191 loser:
192     return NULL;
193 }
194 
195 SECStatus
CERT_EncodeNameConstraintsExtension(PLArenaPool * arena,CERTNameConstraints * value,SECItem * encodedValue)196 CERT_EncodeNameConstraintsExtension(PLArenaPool *arena,
197                                     CERTNameConstraints *value,
198                                     SECItem *encodedValue)
199 {
200     SECStatus rv = SECSuccess;
201 
202     rv = cert_EncodeNameConstraints(value, arena, encodedValue);
203     return rv;
204 }
205 
206 CERTNameConstraints *
CERT_DecodeNameConstraintsExtension(PLArenaPool * arena,const SECItem * encodedConstraints)207 CERT_DecodeNameConstraintsExtension(PLArenaPool *arena,
208                                     const SECItem *encodedConstraints)
209 {
210     return cert_DecodeNameConstraints(arena, encodedConstraints);
211 }
212 
213 CERTAuthInfoAccess **
CERT_DecodeAuthInfoAccessExtension(PLArenaPool * reqArena,const SECItem * encodedExtension)214 CERT_DecodeAuthInfoAccessExtension(PLArenaPool *reqArena,
215                                    const SECItem *encodedExtension)
216 {
217     CERTAuthInfoAccess **info = NULL;
218     SECStatus rv;
219     int i;
220     SECItem *newEncodedExtension;
221 
222     if (!reqArena) {
223         PORT_SetError(SEC_ERROR_INVALID_ARGS);
224         return NULL;
225     }
226 
227     newEncodedExtension = SECITEM_ArenaDupItem(reqArena, encodedExtension);
228     if (!newEncodedExtension) {
229         return NULL;
230     }
231 
232     rv = SEC_QuickDERDecodeItem(reqArena, &info, CERTAuthInfoAccessTemplate,
233                                 newEncodedExtension);
234     if (rv != SECSuccess || info == NULL) {
235         return NULL;
236     }
237 
238     for (i = 0; info[i] != NULL; i++) {
239         info[i]->location =
240             CERT_DecodeGeneralName(reqArena, &(info[i]->derLocation), NULL);
241     }
242     return info;
243 }
244 
245 SECStatus
CERT_EncodeInfoAccessExtension(PLArenaPool * arena,CERTAuthInfoAccess ** info,SECItem * dest)246 CERT_EncodeInfoAccessExtension(PLArenaPool *arena, CERTAuthInfoAccess **info,
247                                SECItem *dest)
248 {
249     SECItem *dummy;
250     int i;
251 
252     PORT_Assert(info != NULL);
253     PORT_Assert(dest != NULL);
254     if (info == NULL || dest == NULL) {
255         return SECFailure;
256     }
257 
258     for (i = 0; info[i] != NULL; i++) {
259         if (CERT_EncodeGeneralName(info[i]->location, &(info[i]->derLocation),
260                                    arena) == NULL)
261             /* Note that this may leave some of the locations filled in. */
262             return SECFailure;
263     }
264     dummy = SEC_ASN1EncodeItem(arena, dest, &info, CERTAuthInfoAccessTemplate);
265     if (dummy == NULL) {
266         return SECFailure;
267     }
268     return SECSuccess;
269 }
270