blob: a8605ce0a61ca98d3131286b30687728788222aa [file] [log] [blame]
Juan Castilloa57a4d52015-04-02 15:44:20 +01001/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * X509 parser based on PolarSSL
33 *
34 * This module implements functions to check the integrity of a X509v3
35 * certificate ASN.1 structure and extract authentication parameters from the
36 * extensions field, such as an image hash or a public key.
37 */
38
39#include <assert.h>
40#include <img_parser_mod.h>
41#include <mbedtls_common.h>
42#include <stddef.h>
43#include <stdint.h>
44#include <string.h>
45
46/* mbedTLS headers */
47#include <polarssl/asn1.h>
48#include <polarssl/oid.h>
49#include <polarssl/platform.h>
50
51/* Maximum OID string length ("a.b.c.d.e.f ...") */
52#define MAX_OID_STR_LEN 64
53
54#define LIB_NAME "mbedTLS X509v3"
55
56/* Temporary variables to speed up the authentication parameters search. These
57 * variables are assigned once during the integrity check and used any time an
58 * authentication parameter is requested, so we do not have to parse the image
59 * again */
60static asn1_buf tbs;
61static asn1_buf v3_ext;
62static asn1_buf pk;
63static asn1_buf sig_alg;
64static asn1_buf signature;
65
66/*
67 * Get X509v3 extension
68 *
69 * Global variable 'v3_ext' must point to the extensions region
70 * in the certificate. No need to check for errors since the image has passed
71 * the integrity check.
72 */
73static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
74{
75 int oid_len;
76 size_t len;
77 unsigned char *end_ext_data, *end_ext_octet;
78 unsigned char *p;
79 const unsigned char *end;
80 char oid_str[MAX_OID_STR_LEN];
81 asn1_buf extn_oid;
82 int is_critical;
83
84 assert(oid != NULL);
85
86 p = v3_ext.p;
87 end = v3_ext.p + v3_ext.len;
88
89 asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
90
91 while (p < end) {
92 memset(&extn_oid, 0x0, sizeof(extn_oid));
93 is_critical = 0; /* DEFAULT FALSE */
94
95 asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
96 end_ext_data = p + len;
97
98 /* Get extension ID */
99 extn_oid.tag = *p;
100 asn1_get_tag(&p, end, &extn_oid.len, ASN1_OID);
101 extn_oid.p = p;
102 p += extn_oid.len;
103
104 /* Get optional critical */
105 asn1_get_bool(&p, end_ext_data, &is_critical);
106
107 /* Extension data */
108 asn1_get_tag(&p, end_ext_data, &len, ASN1_OCTET_STRING);
109 end_ext_octet = p + len;
110
111 /* Detect requested extension */
112 oid_len = oid_get_numeric_string(oid_str,
113 MAX_OID_STR_LEN, &extn_oid);
114 if (oid_len == POLARSSL_ERR_OID_BUF_TOO_SMALL) {
115 return IMG_PARSER_ERR;
116 }
117 if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
118 *ext = (void *)p;
119 *ext_len = (unsigned int)len;
120 return IMG_PARSER_OK;
121 }
122
123 /* Next */
124 p = end_ext_octet;
125 }
126
127 return IMG_PARSER_ERR_NOT_FOUND;
128}
129
130
131/*
132 * Check the integrity of the certificate ASN.1 structure.
133 * Extract the relevant data that will be used later during authentication.
134 */
135static int cert_parse(void *img, unsigned int img_len)
136{
137 int ret, is_critical;
138 size_t len;
139 unsigned char *p, *end, *crt_end;
140 asn1_buf sig_alg1, sig_alg2;
141
142 p = (unsigned char *)img;
143 len = img_len;
144 end = p + len;
145
146 /*
147 * Certificate ::= SEQUENCE {
148 * tbsCertificate TBSCertificate,
149 * signatureAlgorithm AlgorithmIdentifier,
150 * signatureValue BIT STRING }
151 */
152 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
153 if (ret != 0) {
154 return IMG_PARSER_ERR_FORMAT;
155 }
156
157 if (len > (size_t)(end - p)) {
158 return IMG_PARSER_ERR_FORMAT;
159 }
160 crt_end = p + len;
161
162 /*
163 * TBSCertificate ::= SEQUENCE {
164 */
165 tbs.p = p;
166 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
167 if (ret != 0) {
168 return IMG_PARSER_ERR_FORMAT;
169 }
170 end = p + len;
171 tbs.len = end - tbs.p;
172
173 /*
174 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
175 */
176 ret = asn1_get_tag(&p, end, &len,
177 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0);
178 if (ret != 0) {
179 return IMG_PARSER_ERR_FORMAT;
180 }
181 p += len;
182
183 /*
184 * CertificateSerialNumber ::= INTEGER
185 */
186 ret = asn1_get_tag(&p, end, &len, ASN1_INTEGER);
187 if (ret != 0) {
188 return IMG_PARSER_ERR_FORMAT;
189 }
190 p += len;
191
192 /*
193 * signature AlgorithmIdentifier
194 */
195 sig_alg1.p = p;
196 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
197 if (ret != 0) {
198 return IMG_PARSER_ERR_FORMAT;
199 }
200 if ((end - p) < 1) {
201 return IMG_PARSER_ERR_FORMAT;
202 }
203 sig_alg1.len = (p + len) - sig_alg1.p;
204 p += len;
205
206 /*
207 * issuer Name
208 */
209 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
210 if (ret != 0) {
211 return IMG_PARSER_ERR_FORMAT;
212 }
213 p += len;
214
215 /*
216 * Validity ::= SEQUENCE {
217 * notBefore Time,
218 * notAfter Time }
219 *
220 */
221 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
222 if (ret != 0) {
223 return IMG_PARSER_ERR_FORMAT;
224 }
225 p += len;
226
227 /*
228 * subject Name
229 */
230 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
231 if (ret != 0) {
232 return IMG_PARSER_ERR_FORMAT;
233 }
234 p += len;
235
236 /*
237 * SubjectPublicKeyInfo
238 */
239 pk.p = p;
240 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
241 if (ret != 0) {
242 return IMG_PARSER_ERR_FORMAT;
243 }
244 pk.len = (p + len) - pk.p;
245 p += len;
246
247 /*
248 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
249 */
250 ret = asn1_get_tag(&p, end, &len,
251 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1);
252 if (ret != 0) {
253 if (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG) {
254 return IMG_PARSER_ERR_FORMAT;
255 }
256 } else {
257 p += len;
258 }
259
260 /*
261 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
262 */
263 ret = asn1_get_tag(&p, end, &len,
264 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 2);
265 if (ret != 0) {
266 if (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG) {
267 return IMG_PARSER_ERR_FORMAT;
268 }
269 } else {
270 p += len;
271 }
272
273 /*
274 * extensions [3] EXPLICIT Extensions OPTIONAL
275 */
276 ret = asn1_get_tag(&p, end, &len,
277 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3);
278 if (ret != 0) {
279 return IMG_PARSER_ERR_FORMAT;
280 }
281
282 /*
283 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
284 */
285 v3_ext.p = p;
286 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
287 if (ret != 0) {
288 return IMG_PARSER_ERR_FORMAT;
289 }
290 v3_ext.len = (p + len) - v3_ext.p;
291
292 /*
293 * Check extensions integrity
294 */
295 while (p < end) {
296 ret = asn1_get_tag(&p, end, &len,
297 ASN1_CONSTRUCTED | ASN1_SEQUENCE);
298 if (ret != 0) {
299 return IMG_PARSER_ERR_FORMAT;
300 }
301
302 /* Get extension ID */
303 ret = asn1_get_tag(&p, end, &len, ASN1_OID);
304 if (ret != 0) {
305 return IMG_PARSER_ERR_FORMAT;
306 }
307 p += len;
308
309 /* Get optional critical */
310 ret = asn1_get_bool(&p, end, &is_critical);
311 if ((ret != 0) && (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG)) {
312 return IMG_PARSER_ERR_FORMAT;
313 }
314
315 /* Data should be octet string type */
316 ret = asn1_get_tag(&p, end, &len, ASN1_OCTET_STRING);
317 if (ret != 0) {
318 return IMG_PARSER_ERR_FORMAT;
319 }
320 p += len;
321 }
322
323 if (p != end) {
324 return IMG_PARSER_ERR_FORMAT;
325 }
326
327 end = crt_end;
328
329 /*
330 * }
331 * -- end of TBSCertificate
332 *
333 * signatureAlgorithm AlgorithmIdentifier
334 */
335 sig_alg2.p = p;
336 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
337 if (ret != 0) {
338 return IMG_PARSER_ERR_FORMAT;
339 }
340 if ((end - p) < 1) {
341 return IMG_PARSER_ERR_FORMAT;
342 }
343 sig_alg2.len = (p + len) - sig_alg2.p;
344 p += len;
345
346 /* Compare both signature algorithms */
347 if (sig_alg1.len != sig_alg2.len) {
348 return IMG_PARSER_ERR_FORMAT;
349 }
350 if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
351 return IMG_PARSER_ERR_FORMAT;
352 }
353 memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
354
355 /*
356 * signatureValue BIT STRING
357 */
358 signature.p = p;
359 ret = asn1_get_tag(&p, end, &len, ASN1_BIT_STRING);
360 if (ret != 0) {
361 return IMG_PARSER_ERR_FORMAT;
362 }
363 signature.len = (p + len) - signature.p;
364 p += len;
365
366 /* Check certificate length */
367 if (p != end) {
368 return IMG_PARSER_ERR_FORMAT;
369 }
370
371 return IMG_PARSER_OK;
372}
373
374
375/* Exported functions */
376
377static void init(void)
378{
379 mbedtls_init();
380}
381
382static int check_integrity(void *img, unsigned int img_len)
383{
384 return cert_parse(img, img_len);
385}
386
387/*
388 * Extract an authentication parameter from an X509v3 certificate
389 */
390static int get_auth_param(const auth_param_type_desc_t *type_desc,
391 void *img, unsigned int img_len,
392 void **param, unsigned int *param_len)
393{
394 int rc = IMG_PARSER_OK;
395
396 /* We do not use img because the check_integrity function has already
397 * extracted the relevant data (v3_ext, pk, sig_alg, etc) */
398
399 switch (type_desc->type) {
400 case AUTH_PARAM_RAW_DATA:
401 /* Data to be signed */
402 *param = (void *)tbs.p;
403 *param_len = (unsigned int)tbs.len;
404 break;
405 case AUTH_PARAM_HASH:
406 /* All these parameters are included as X509v3 extensions */
407 rc = get_ext(type_desc->cookie, param, param_len);
408 break;
409 case AUTH_PARAM_PUB_KEY:
410 if (type_desc->cookie != 0) {
411 /* Get public key from extension */
412 rc = get_ext(type_desc->cookie, param, param_len);
413 } else {
414 /* Get the subject public key */
415 *param = (void *)pk.p;
416 *param_len = (unsigned int)pk.len;
417 }
418 break;
419 case AUTH_PARAM_SIG_ALG:
420 /* Get the certificate signature algorithm */
421 *param = (void *)sig_alg.p;
422 *param_len = (unsigned int)sig_alg.len;
423 break;
424 case AUTH_PARAM_SIG:
425 /* Get the certificate signature */
426 *param = (void *)signature.p;
427 *param_len = (unsigned int)signature.len;
428 break;
429 default:
430 rc = IMG_PARSER_ERR_NOT_FOUND;
431 break;
432 }
433
434 return rc;
435}
436
437REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
438 check_integrity, get_auth_param);