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  * Code for dealing with X509.V3 extensions.
7  */
8 
9 #include "cert.h"
10 #include "secitem.h"
11 #include "secoid.h"
12 #include "secder.h"
13 #include "secasn1.h"
14 #include "certxutl.h"
15 #include "secerr.h"
16 
17 SECStatus
CERT_FindCertExtensionByOID(CERTCertificate * cert,SECItem * oid,SECItem * value)18 CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, SECItem *value)
19 {
20     return (cert_FindExtensionByOID(cert->extensions, oid, value));
21 }
22 
23 SECStatus
CERT_FindCertExtension(const CERTCertificate * cert,int tag,SECItem * value)24 CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value)
25 {
26     return (cert_FindExtension(cert->extensions, tag, value));
27 }
28 
29 static void
SetExts(void * object,CERTCertExtension ** exts)30 SetExts(void *object, CERTCertExtension **exts)
31 {
32     CERTCertificate *cert = (CERTCertificate *)object;
33 
34     cert->extensions = exts;
35     DER_SetUInteger(cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3);
36 }
37 
38 void *
CERT_StartCertExtensions(CERTCertificate * cert)39 CERT_StartCertExtensions(CERTCertificate *cert)
40 {
41     return (cert_StartExtensions((void *)cert, cert->arena, SetExts));
42 }
43 
44 /*
45  * get the value of the Netscape Certificate Type Extension
46  */
47 SECStatus
CERT_FindNSCertTypeExtension(CERTCertificate * cert,SECItem * retItem)48 CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
49 {
50 
51     return (CERT_FindBitStringExtension(
52         cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));
53 }
54 
55 /*
56  * get the value of a string type extension
57  */
58 char *
CERT_FindNSStringExtension(CERTCertificate * cert,int oidtag)59 CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
60 {
61     SECItem wrapperItem, tmpItem = { siBuffer, 0 };
62     SECStatus rv;
63     PLArenaPool *arena = NULL;
64     char *retstring = NULL;
65 
66     wrapperItem.data = NULL;
67     tmpItem.data = NULL;
68 
69     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
70 
71     if (!arena) {
72         goto loser;
73     }
74 
75     rv = cert_FindExtension(cert->extensions, oidtag, &wrapperItem);
76     if (rv != SECSuccess) {
77         goto loser;
78     }
79 
80     rv = SEC_QuickDERDecodeItem(
81         arena, &tmpItem, SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem);
82 
83     if (rv != SECSuccess) {
84         goto loser;
85     }
86 
87     retstring = (char *)PORT_Alloc(tmpItem.len + 1);
88     if (retstring == NULL) {
89         goto loser;
90     }
91 
92     PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
93     retstring[tmpItem.len] = '\0';
94 
95 loser:
96     if (arena) {
97         PORT_FreeArena(arena, PR_FALSE);
98     }
99 
100     if (wrapperItem.data) {
101         PORT_Free(wrapperItem.data);
102     }
103 
104     return (retstring);
105 }
106 
107 /*
108  * get the value of the X.509 v3 Key Usage Extension
109  */
110 SECStatus
CERT_FindKeyUsageExtension(CERTCertificate * cert,SECItem * retItem)111 CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
112 {
113 
114     return (CERT_FindBitStringExtension(cert->extensions,
115                                         SEC_OID_X509_KEY_USAGE, retItem));
116 }
117 
118 /*
119  * get the value of the X.509 v3 Key Usage Extension
120  */
121 SECStatus
CERT_FindSubjectKeyIDExtension(CERTCertificate * cert,SECItem * retItem)122 CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
123 {
124 
125     SECStatus rv;
126     SECItem encodedValue = { siBuffer, NULL, 0 };
127     SECItem decodedValue = { siBuffer, NULL, 0 };
128 
129     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID,
130                             &encodedValue);
131     if (rv == SECSuccess) {
132         PORTCheapArenaPool tmpArena;
133         PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
134         rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodedValue,
135                                     SEC_ASN1_GET(SEC_OctetStringTemplate),
136                                     &encodedValue);
137         if (rv == SECSuccess) {
138             rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
139         }
140         PORT_DestroyCheapArena(&tmpArena);
141     }
142     SECITEM_FreeItem(&encodedValue, PR_FALSE);
143     return rv;
144 }
145 
146 SECStatus
CERT_FindBasicConstraintExten(CERTCertificate * cert,CERTBasicConstraints * value)147 CERT_FindBasicConstraintExten(CERTCertificate *cert,
148                               CERTBasicConstraints *value)
149 {
150     SECItem encodedExtenValue;
151     SECStatus rv;
152 
153     encodedExtenValue.data = NULL;
154     encodedExtenValue.len = 0;
155 
156     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
157                             &encodedExtenValue);
158     if (rv != SECSuccess) {
159         return (rv);
160     }
161 
162     rv = CERT_DecodeBasicConstraintValue(value, &encodedExtenValue);
163 
164     /* free the raw extension data */
165     PORT_Free(encodedExtenValue.data);
166     encodedExtenValue.data = NULL;
167 
168     return (rv);
169 }
170 
171 CERTAuthKeyID *
CERT_FindAuthKeyIDExten(PLArenaPool * arena,CERTCertificate * cert)172 CERT_FindAuthKeyIDExten(PLArenaPool *arena, CERTCertificate *cert)
173 {
174     SECItem encodedExtenValue;
175     SECStatus rv;
176     CERTAuthKeyID *ret;
177 
178     encodedExtenValue.data = NULL;
179     encodedExtenValue.len = 0;
180 
181     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
182                             &encodedExtenValue);
183     if (rv != SECSuccess) {
184         return (NULL);
185     }
186 
187     ret = CERT_DecodeAuthKeyID(arena, &encodedExtenValue);
188 
189     PORT_Free(encodedExtenValue.data);
190     encodedExtenValue.data = NULL;
191 
192     return (ret);
193 }
194 
195 SECStatus
CERT_CheckCertUsage(CERTCertificate * cert,unsigned char usage)196 CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
197 {
198     SECItem keyUsage;
199     SECStatus rv;
200 
201     /* There is no extension, v1 or v2 certificate */
202     if (cert->extensions == NULL) {
203         return (SECSuccess);
204     }
205 
206     keyUsage.data = NULL;
207 
208     /* This code formerly ignored the Key Usage extension if it was
209     ** marked non-critical.  That was wrong.  Since we do understand it,
210     ** we are obligated to honor it, whether or not it is critical.
211     */
212     rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
213     if (rv == SECFailure) {
214         rv = (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) ? SECSuccess
215                                                                 : SECFailure;
216     } else if (!keyUsage.data || !(keyUsage.data[0] & usage)) {
217         PORT_SetError(SEC_ERROR_CERT_USAGES_INVALID);
218         rv = SECFailure;
219     }
220     PORT_Free(keyUsage.data);
221     return (rv);
222 }
223