1 /*
2  * Copyright (c) 2021, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 /** \file cc3xx_internal_asn1_util.c
9  *
10  * This file contains the implementation of the internal functions and
11  * utilities to perform parsing of ASN-1 encoded key buffers
12  *
13  */
14 
15 #include "cc3xx_internal_asn1_util.h"
16 #include "psa/crypto.h"
17 
18 #define CC3XX_ASN1_CHK_ADD(g, f)                                               \
19     do {                                                                       \
20         if ((ret = (f)) < 0)                                                   \
21             return (ret);                                                      \
22         else                                                                   \
23             (g) += ret;                                                        \
24     } while (0)
25 
26 /**
27  * \ingroup internal_asn1_util
28  */
cc3xx_asn1_write_len(unsigned char ** p,const unsigned char * start,size_t len)29 int cc3xx_asn1_write_len(unsigned char **p, const unsigned char *start,
30                          size_t len)
31 {
32     if (len < 0x80) {
33         if (*p - start < 1) {
34             return (PSA_ERROR_BUFFER_TOO_SMALL);
35         }
36 
37         *--(*p) = (unsigned char)len;
38         return (1);
39     }
40 
41     if (len <= 0xFF) {
42         if (*p - start < 2) {
43             return (PSA_ERROR_BUFFER_TOO_SMALL);
44         }
45 
46         *--(*p) = (unsigned char)len;
47         *--(*p) = 0x81;
48         return (2);
49     }
50 
51     if (len <= 0xFFFF) {
52         if (*p - start < 3) {
53             return (PSA_ERROR_BUFFER_TOO_SMALL);
54         }
55 
56         *--(*p) = (len)&0xFF;
57         *--(*p) = (len >> 8) & 0xFF;
58         *--(*p) = 0x82;
59         return (3);
60     }
61 
62     if (len <= 0xFFFFFF) {
63         if (*p - start < 4) {
64             return (PSA_ERROR_BUFFER_TOO_SMALL);
65         }
66 
67         *--(*p) = (len)&0xFF;
68         *--(*p) = (len >> 8) & 0xFF;
69         *--(*p) = (len >> 16) & 0xFF;
70         *--(*p) = 0x83;
71         return (4);
72     }
73 
74     return PSA_ERROR_GENERIC_ERROR;
75 }
76 
77 /**
78  * \ingroup internal_asn1_util
79  */
cc3xx_asn1_write_tag(unsigned char ** p,const unsigned char * start,unsigned char tag)80 int cc3xx_asn1_write_tag(unsigned char **p, const unsigned char *start,
81                          unsigned char tag)
82 {
83     if (*p - start < 1) {
84         return (PSA_ERROR_BUFFER_TOO_SMALL);
85     }
86 
87     *--(*p) = tag;
88 
89     return (1);
90 }
91 
92 /**
93  * \ingroup internal_asn1_util
94  */
cc3xx_asn1_write_big_integer(unsigned char ** p,const unsigned char * start,uint8_t * data,size_t data_size)95 int cc3xx_asn1_write_big_integer(unsigned char **p, const unsigned char *start,
96                                  uint8_t *data, size_t data_size)
97 {
98     int ret = PSA_ERROR_GENERIC_ERROR;
99     size_t len = data_size;
100 
101     if (*p < start || (size_t)(*p - start) < len) {
102         return (PSA_ERROR_BUFFER_TOO_SMALL);
103     }
104 
105     (*p) -= len;
106     CC_PalMemCopy(*p, data, data_size);
107 
108     /* DER format assumes 2s complement for numbers, so the leftmost bit
109      * should be 0 for positive numbers and 1 for negative numbers.
110      *
111      * FIXME: Check if there is any chance that we will use negative numbers. If
112      * so this should be done (was X->s == 1)
113      */
114     if (**p & 0x80) {
115         if (*p - start < 1) {
116             return (PSA_ERROR_BUFFER_TOO_SMALL);
117         }
118 
119         *--(*p) = 0x00;
120         len += 1;
121     }
122 
123     CC3XX_ASN1_CHK_ADD(len, cc3xx_asn1_write_len(p, start, len));
124     CC3XX_ASN1_CHK_ADD(len,
125                        cc3xx_asn1_write_tag(p, start, CC3XX_TAG_ASN1_INTEGER));
126 
127     ret = (int)len;
128 
129     return (ret);
130 }
131 
asn1_write_tagged_int(unsigned char ** p,unsigned char * start,int val,int tag)132 static int asn1_write_tagged_int(unsigned char **p, unsigned char *start,
133                                  int val, int tag)
134 {
135     int ret; /* This is used by the CC3XX_ASN1_CHK_ADD macro */
136     size_t len = 0;
137 
138     do {
139         if (*p - start < 1) {
140             return (PSA_ERROR_BUFFER_TOO_SMALL);
141         }
142         len += 1;
143         *--(*p) = val & 0xff;
144         val >>= 8;
145     } while (val > 0);
146 
147     if (**p & 0x80) {
148         if (*p - start < 1) {
149             return (PSA_ERROR_BUFFER_TOO_SMALL);
150         }
151         *--(*p) = 0x00;
152         len += 1;
153     }
154 
155     CC3XX_ASN1_CHK_ADD(len, cc3xx_asn1_write_len(p, start, len));
156     CC3XX_ASN1_CHK_ADD(len, cc3xx_asn1_write_tag(p, start, tag));
157 
158     return (len);
159 }
160 
asn1_get_tagged_int(unsigned char ** p,const unsigned char * end,int tag,int * val)161 static int asn1_get_tagged_int(unsigned char **p, const unsigned char *end,
162                                int tag, int *val)
163 {
164     int ret = PSA_ERROR_CORRUPTION_DETECTED;
165     size_t len;
166 
167     if ((ret = cc3xx_asn1_get_tag(p, end, &len, tag)) != 0) {
168         return (ret);
169     }
170 
171     /*
172      * len==0 is malformed (0 must be represented as 020100 for INTEGER,
173      * or 0A0100 for ENUMERATED tags
174      */
175     if (len == 0) {
176         return (PSA_ERROR_BUFFER_TOO_SMALL);
177     }
178 
179     if ((**p & 0x80) != 0) {
180         return (PSA_ERROR_BUFFER_TOO_SMALL);
181     }
182 
183     /* Skip leading zeros. */
184     while (len > 0 && **p == 0) {
185         ++(*p);
186         --len;
187     }
188 
189     /* Reject integers that don't fit in an int. This code assumes that
190      * the int type has no padding bit. */
191     if (len > sizeof(int)) {
192         return (PSA_ERROR_BUFFER_TOO_SMALL);
193     }
194     if (len == sizeof(int) && (**p & 0x80) != 0) {
195         return (PSA_ERROR_BUFFER_TOO_SMALL);
196     }
197 
198     *val = 0;
199     while (len-- > 0) {
200         *val = (*val << 8) | **p;
201         (*p)++;
202     }
203 
204     return (PSA_SUCCESS);
205 }
206 
207 /** \defgroup internal_asn1_util Internal ASN-1 parsing functions
208  *
209  *  Internal functions used by the driver to parse objets in ASN-1 format
210  *
211  *  @{
212  */
cc3xx_asn1_get_tag(unsigned char ** p,const unsigned char * end,size_t * len,int tag)213 psa_status_t cc3xx_asn1_get_tag(unsigned char **p, const unsigned char *end,
214                                 size_t *len, int tag)
215 {
216     if ((end - *p) < 1) {
217         return (PSA_ERROR_BUFFER_TOO_SMALL);
218     }
219 
220     if (**p != tag) {
221         return (PSA_ERROR_GENERIC_ERROR);
222     }
223 
224     (*p)++;
225 
226     return (cc3xx_asn1_get_len(p, end, len));
227 }
228 
cc3xx_asn1_get_len(unsigned char ** p,const unsigned char * end,size_t * len)229 psa_status_t cc3xx_asn1_get_len(unsigned char **p, const unsigned char *end,
230                                 size_t *len)
231 {
232     if ((end - *p) < 1) {
233         return (PSA_ERROR_BUFFER_TOO_SMALL);
234     }
235 
236     if ((**p & 0x80) == 0) {
237         *len = *(*p)++;
238     } else {
239         switch (**p & 0x7F) {
240         case 1:
241             if ((end - *p) < 2) {
242                 return (PSA_ERROR_BUFFER_TOO_SMALL);
243             }
244 
245             *len = (*p)[1];
246             (*p) += 2;
247             break;
248 
249         case 2:
250             if ((end - *p) < 3) {
251                 return (PSA_ERROR_BUFFER_TOO_SMALL);
252             }
253 
254             *len = ((size_t)(*p)[1] << 8) | (*p)[2];
255             (*p) += 3;
256             break;
257 
258         case 3:
259             if ((end - *p) < 4) {
260                 return (PSA_ERROR_BUFFER_TOO_SMALL);
261             }
262 
263             *len = ((size_t)(*p)[1] << 16) | ((size_t)(*p)[2] << 8) | (*p)[3];
264             (*p) += 4;
265             break;
266 
267         case 4:
268             if ((end - *p) < 5) {
269                 return (PSA_ERROR_BUFFER_TOO_SMALL);
270             }
271 
272             *len = ((size_t)(*p)[1] << 24) | ((size_t)(*p)[2] << 16) |
273                    ((size_t)(*p)[3] << 8) | (*p)[4];
274             (*p) += 5;
275             break;
276 
277         default:
278             return (PSA_ERROR_BUFFER_TOO_SMALL);
279         }
280     }
281 
282     if (*len > (size_t)(end - *p)) {
283         return (PSA_ERROR_BUFFER_TOO_SMALL);
284     }
285 
286     return (PSA_SUCCESS);
287 }
288 
cc3xx_asn1_get_int(unsigned char ** p,const unsigned char * end,int * val)289 psa_status_t cc3xx_asn1_get_int(unsigned char **p, const unsigned char *end,
290                                 int *val)
291 {
292     return (asn1_get_tagged_int(p, end, CC3XX_TAG_ASN1_INTEGER, val));
293 }
294 
cc3xx_asn1_write_int(unsigned char ** p,unsigned char * start,int val)295 int cc3xx_asn1_write_int(unsigned char **p, unsigned char *start, int val)
296 {
297     return (asn1_write_tagged_int(p, start, val, CC3XX_TAG_ASN1_INTEGER));
298 }
299 /** @} */ // end of internal_asn1_util
300