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