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