1e71b7053SJung-uk Kim /*
2*b077aed3SPierre Pronchery * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim *
4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy
6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html
8e71b7053SJung-uk Kim */
9e71b7053SJung-uk Kim
10e71b7053SJung-uk Kim #include <stdio.h>
11e71b7053SJung-uk Kim #include "internal/cryptlib.h"
12e71b7053SJung-uk Kim #include "internal/numbers.h"
13e71b7053SJung-uk Kim #include <openssl/asn1t.h>
14e71b7053SJung-uk Kim #include <openssl/bn.h>
1517f01e99SJung-uk Kim #include "asn1_local.h"
16e71b7053SJung-uk Kim
17e71b7053SJung-uk Kim /*
18e71b7053SJung-uk Kim * Custom primitive types for handling int32_t, int64_t, uint32_t, uint64_t.
19e71b7053SJung-uk Kim * This converts between an ASN1_INTEGER and those types directly.
20e71b7053SJung-uk Kim * This is preferred to using the LONG / ZLONG primitives.
21e71b7053SJung-uk Kim */
22e71b7053SJung-uk Kim
23e71b7053SJung-uk Kim /*
24e71b7053SJung-uk Kim * We abuse the ASN1_ITEM fields |size| as a flags field
25e71b7053SJung-uk Kim */
26e71b7053SJung-uk Kim #define INTxx_FLAG_ZERO_DEFAULT (1<<0)
27e71b7053SJung-uk Kim #define INTxx_FLAG_SIGNED (1<<1)
28e71b7053SJung-uk Kim
uint64_new(ASN1_VALUE ** pval,const ASN1_ITEM * it)29e71b7053SJung-uk Kim static int uint64_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
30e71b7053SJung-uk Kim {
31e71b7053SJung-uk Kim if ((*pval = (ASN1_VALUE *)OPENSSL_zalloc(sizeof(uint64_t))) == NULL) {
32*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
33e71b7053SJung-uk Kim return 0;
34e71b7053SJung-uk Kim }
35e71b7053SJung-uk Kim return 1;
36e71b7053SJung-uk Kim }
37e71b7053SJung-uk Kim
uint64_free(ASN1_VALUE ** pval,const ASN1_ITEM * it)38e71b7053SJung-uk Kim static void uint64_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
39e71b7053SJung-uk Kim {
40e71b7053SJung-uk Kim OPENSSL_free(*pval);
41e71b7053SJung-uk Kim *pval = NULL;
42e71b7053SJung-uk Kim }
43e71b7053SJung-uk Kim
uint64_clear(ASN1_VALUE ** pval,const ASN1_ITEM * it)44e71b7053SJung-uk Kim static void uint64_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
45e71b7053SJung-uk Kim {
46e71b7053SJung-uk Kim **(uint64_t **)pval = 0;
47e71b7053SJung-uk Kim }
48e71b7053SJung-uk Kim
uint64_i2c(const ASN1_VALUE ** pval,unsigned char * cont,int * putype,const ASN1_ITEM * it)49*b077aed3SPierre Pronchery static int uint64_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
50e71b7053SJung-uk Kim const ASN1_ITEM *it)
51e71b7053SJung-uk Kim {
52e71b7053SJung-uk Kim uint64_t utmp;
53e71b7053SJung-uk Kim int neg = 0;
54e71b7053SJung-uk Kim /* this exists to bypass broken gcc optimization */
55e71b7053SJung-uk Kim char *cp = (char *)*pval;
56e71b7053SJung-uk Kim
57e71b7053SJung-uk Kim /* use memcpy, because we may not be uint64_t aligned */
58e71b7053SJung-uk Kim memcpy(&utmp, cp, sizeof(utmp));
59e71b7053SJung-uk Kim
60e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_ZERO_DEFAULT) == INTxx_FLAG_ZERO_DEFAULT
61e71b7053SJung-uk Kim && utmp == 0)
62e71b7053SJung-uk Kim return -1;
63e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == INTxx_FLAG_SIGNED
64e71b7053SJung-uk Kim && (int64_t)utmp < 0) {
65*b077aed3SPierre Pronchery /* ossl_i2c_uint64_int() assumes positive values */
66e71b7053SJung-uk Kim utmp = 0 - utmp;
67e71b7053SJung-uk Kim neg = 1;
68e71b7053SJung-uk Kim }
69e71b7053SJung-uk Kim
70*b077aed3SPierre Pronchery return ossl_i2c_uint64_int(cont, utmp, neg);
71e71b7053SJung-uk Kim }
72e71b7053SJung-uk Kim
uint64_c2i(ASN1_VALUE ** pval,const unsigned char * cont,int len,int utype,char * free_cont,const ASN1_ITEM * it)73e71b7053SJung-uk Kim static int uint64_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
74e71b7053SJung-uk Kim int utype, char *free_cont, const ASN1_ITEM *it)
75e71b7053SJung-uk Kim {
76e71b7053SJung-uk Kim uint64_t utmp = 0;
77e71b7053SJung-uk Kim char *cp;
78e71b7053SJung-uk Kim int neg = 0;
79e71b7053SJung-uk Kim
80e71b7053SJung-uk Kim if (*pval == NULL && !uint64_new(pval, it))
81e71b7053SJung-uk Kim return 0;
82e71b7053SJung-uk Kim
83e71b7053SJung-uk Kim cp = (char *)*pval;
84e71b7053SJung-uk Kim
85e71b7053SJung-uk Kim /*
86e71b7053SJung-uk Kim * Strictly speaking, zero length is malformed. However, long_c2i
87e71b7053SJung-uk Kim * (x_long.c) encodes 0 as a zero length INTEGER (wrongly, of course),
88e71b7053SJung-uk Kim * so for the sake of backward compatibility, we still decode zero
89e71b7053SJung-uk Kim * length INTEGERs as the number zero.
90e71b7053SJung-uk Kim */
91e71b7053SJung-uk Kim if (len == 0)
92e71b7053SJung-uk Kim goto long_compat;
93e71b7053SJung-uk Kim
94*b077aed3SPierre Pronchery if (!ossl_c2i_uint64_int(&utmp, &neg, &cont, len))
95e71b7053SJung-uk Kim return 0;
96e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == 0 && neg) {
97*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_NEGATIVE_VALUE);
98e71b7053SJung-uk Kim return 0;
99e71b7053SJung-uk Kim }
100e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == INTxx_FLAG_SIGNED
101e71b7053SJung-uk Kim && !neg && utmp > INT64_MAX) {
102*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
103e71b7053SJung-uk Kim return 0;
104e71b7053SJung-uk Kim }
105e71b7053SJung-uk Kim if (neg)
106*b077aed3SPierre Pronchery /* ossl_c2i_uint64_int() returns positive values */
107e71b7053SJung-uk Kim utmp = 0 - utmp;
108e71b7053SJung-uk Kim
109e71b7053SJung-uk Kim long_compat:
110e71b7053SJung-uk Kim memcpy(cp, &utmp, sizeof(utmp));
111e71b7053SJung-uk Kim return 1;
112e71b7053SJung-uk Kim }
113e71b7053SJung-uk Kim
uint64_print(BIO * out,const ASN1_VALUE ** pval,const ASN1_ITEM * it,int indent,const ASN1_PCTX * pctx)114*b077aed3SPierre Pronchery static int uint64_print(BIO *out, const ASN1_VALUE **pval, const ASN1_ITEM *it,
115e71b7053SJung-uk Kim int indent, const ASN1_PCTX *pctx)
116e71b7053SJung-uk Kim {
117e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == INTxx_FLAG_SIGNED)
118e71b7053SJung-uk Kim return BIO_printf(out, "%jd\n", **(int64_t **)pval);
119e71b7053SJung-uk Kim return BIO_printf(out, "%ju\n", **(uint64_t **)pval);
120e71b7053SJung-uk Kim }
121e71b7053SJung-uk Kim
122e71b7053SJung-uk Kim /* 32-bit variants */
123e71b7053SJung-uk Kim
uint32_new(ASN1_VALUE ** pval,const ASN1_ITEM * it)124e71b7053SJung-uk Kim static int uint32_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
125e71b7053SJung-uk Kim {
126e71b7053SJung-uk Kim if ((*pval = (ASN1_VALUE *)OPENSSL_zalloc(sizeof(uint32_t))) == NULL) {
127*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
128e71b7053SJung-uk Kim return 0;
129e71b7053SJung-uk Kim }
130e71b7053SJung-uk Kim return 1;
131e71b7053SJung-uk Kim }
132e71b7053SJung-uk Kim
uint32_free(ASN1_VALUE ** pval,const ASN1_ITEM * it)133e71b7053SJung-uk Kim static void uint32_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
134e71b7053SJung-uk Kim {
135e71b7053SJung-uk Kim OPENSSL_free(*pval);
136e71b7053SJung-uk Kim *pval = NULL;
137e71b7053SJung-uk Kim }
138e71b7053SJung-uk Kim
uint32_clear(ASN1_VALUE ** pval,const ASN1_ITEM * it)139e71b7053SJung-uk Kim static void uint32_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
140e71b7053SJung-uk Kim {
141e71b7053SJung-uk Kim **(uint32_t **)pval = 0;
142e71b7053SJung-uk Kim }
143e71b7053SJung-uk Kim
uint32_i2c(const ASN1_VALUE ** pval,unsigned char * cont,int * putype,const ASN1_ITEM * it)144*b077aed3SPierre Pronchery static int uint32_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
145e71b7053SJung-uk Kim const ASN1_ITEM *it)
146e71b7053SJung-uk Kim {
147e71b7053SJung-uk Kim uint32_t utmp;
148e71b7053SJung-uk Kim int neg = 0;
149e71b7053SJung-uk Kim /* this exists to bypass broken gcc optimization */
150e71b7053SJung-uk Kim char *cp = (char *)*pval;
151e71b7053SJung-uk Kim
152e71b7053SJung-uk Kim /* use memcpy, because we may not be uint32_t aligned */
153e71b7053SJung-uk Kim memcpy(&utmp, cp, sizeof(utmp));
154e71b7053SJung-uk Kim
155e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_ZERO_DEFAULT) == INTxx_FLAG_ZERO_DEFAULT
156e71b7053SJung-uk Kim && utmp == 0)
157e71b7053SJung-uk Kim return -1;
158e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == INTxx_FLAG_SIGNED
159e71b7053SJung-uk Kim && (int32_t)utmp < 0) {
160*b077aed3SPierre Pronchery /* ossl_i2c_uint64_int() assumes positive values */
161e71b7053SJung-uk Kim utmp = 0 - utmp;
162e71b7053SJung-uk Kim neg = 1;
163e71b7053SJung-uk Kim }
164e71b7053SJung-uk Kim
165*b077aed3SPierre Pronchery return ossl_i2c_uint64_int(cont, (uint64_t)utmp, neg);
166e71b7053SJung-uk Kim }
167e71b7053SJung-uk Kim
168e71b7053SJung-uk Kim /*
169e71b7053SJung-uk Kim * Absolute value of INT32_MIN: we can't just use -INT32_MIN as it produces
170e71b7053SJung-uk Kim * overflow warnings.
171e71b7053SJung-uk Kim */
172e71b7053SJung-uk Kim
173e71b7053SJung-uk Kim #define ABS_INT32_MIN ((uint32_t)INT32_MAX + 1)
174e71b7053SJung-uk Kim
uint32_c2i(ASN1_VALUE ** pval,const unsigned char * cont,int len,int utype,char * free_cont,const ASN1_ITEM * it)175e71b7053SJung-uk Kim static int uint32_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
176e71b7053SJung-uk Kim int utype, char *free_cont, const ASN1_ITEM *it)
177e71b7053SJung-uk Kim {
178e71b7053SJung-uk Kim uint64_t utmp = 0;
179e71b7053SJung-uk Kim uint32_t utmp2 = 0;
180e71b7053SJung-uk Kim char *cp;
181e71b7053SJung-uk Kim int neg = 0;
182e71b7053SJung-uk Kim
183e71b7053SJung-uk Kim if (*pval == NULL && !uint64_new(pval, it))
184e71b7053SJung-uk Kim return 0;
185e71b7053SJung-uk Kim
186e71b7053SJung-uk Kim cp = (char *)*pval;
187e71b7053SJung-uk Kim
188e71b7053SJung-uk Kim /*
189e71b7053SJung-uk Kim * Strictly speaking, zero length is malformed. However, long_c2i
190e71b7053SJung-uk Kim * (x_long.c) encodes 0 as a zero length INTEGER (wrongly, of course),
191e71b7053SJung-uk Kim * so for the sake of backward compatibility, we still decode zero
192e71b7053SJung-uk Kim * length INTEGERs as the number zero.
193e71b7053SJung-uk Kim */
194e71b7053SJung-uk Kim if (len == 0)
195e71b7053SJung-uk Kim goto long_compat;
196e71b7053SJung-uk Kim
197*b077aed3SPierre Pronchery if (!ossl_c2i_uint64_int(&utmp, &neg, &cont, len))
198e71b7053SJung-uk Kim return 0;
199e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == 0 && neg) {
200*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_NEGATIVE_VALUE);
201e71b7053SJung-uk Kim return 0;
202e71b7053SJung-uk Kim }
203e71b7053SJung-uk Kim if (neg) {
204e71b7053SJung-uk Kim if (utmp > ABS_INT32_MIN) {
205*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL);
206e71b7053SJung-uk Kim return 0;
207e71b7053SJung-uk Kim }
208e71b7053SJung-uk Kim utmp = 0 - utmp;
209e71b7053SJung-uk Kim } else {
210e71b7053SJung-uk Kim if (((it->size & INTxx_FLAG_SIGNED) != 0 && utmp > INT32_MAX)
211e71b7053SJung-uk Kim || ((it->size & INTxx_FLAG_SIGNED) == 0 && utmp > UINT32_MAX)) {
212*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
213e71b7053SJung-uk Kim return 0;
214e71b7053SJung-uk Kim }
215e71b7053SJung-uk Kim }
216e71b7053SJung-uk Kim
217e71b7053SJung-uk Kim long_compat:
218e71b7053SJung-uk Kim utmp2 = (uint32_t)utmp;
219e71b7053SJung-uk Kim memcpy(cp, &utmp2, sizeof(utmp2));
220e71b7053SJung-uk Kim return 1;
221e71b7053SJung-uk Kim }
222e71b7053SJung-uk Kim
uint32_print(BIO * out,const ASN1_VALUE ** pval,const ASN1_ITEM * it,int indent,const ASN1_PCTX * pctx)223*b077aed3SPierre Pronchery static int uint32_print(BIO *out, const ASN1_VALUE **pval, const ASN1_ITEM *it,
224e71b7053SJung-uk Kim int indent, const ASN1_PCTX *pctx)
225e71b7053SJung-uk Kim {
226e71b7053SJung-uk Kim if ((it->size & INTxx_FLAG_SIGNED) == INTxx_FLAG_SIGNED)
227e71b7053SJung-uk Kim return BIO_printf(out, "%d\n", **(int32_t **)pval);
228e71b7053SJung-uk Kim return BIO_printf(out, "%u\n", **(uint32_t **)pval);
229e71b7053SJung-uk Kim }
230e71b7053SJung-uk Kim
231e71b7053SJung-uk Kim
232e71b7053SJung-uk Kim /* Define the primitives themselves */
233e71b7053SJung-uk Kim
234e71b7053SJung-uk Kim static ASN1_PRIMITIVE_FUNCS uint32_pf = {
235e71b7053SJung-uk Kim NULL, 0,
236e71b7053SJung-uk Kim uint32_new,
237e71b7053SJung-uk Kim uint32_free,
238e71b7053SJung-uk Kim uint32_clear,
239e71b7053SJung-uk Kim uint32_c2i,
240e71b7053SJung-uk Kim uint32_i2c,
241e71b7053SJung-uk Kim uint32_print
242e71b7053SJung-uk Kim };
243e71b7053SJung-uk Kim
244e71b7053SJung-uk Kim static ASN1_PRIMITIVE_FUNCS uint64_pf = {
245e71b7053SJung-uk Kim NULL, 0,
246e71b7053SJung-uk Kim uint64_new,
247e71b7053SJung-uk Kim uint64_free,
248e71b7053SJung-uk Kim uint64_clear,
249e71b7053SJung-uk Kim uint64_c2i,
250e71b7053SJung-uk Kim uint64_i2c,
251e71b7053SJung-uk Kim uint64_print
252e71b7053SJung-uk Kim };
253e71b7053SJung-uk Kim
254e71b7053SJung-uk Kim ASN1_ITEM_start(INT32)
255e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint32_pf,
256e71b7053SJung-uk Kim INTxx_FLAG_SIGNED, "INT32"
257e71b7053SJung-uk Kim ASN1_ITEM_end(INT32)
258e71b7053SJung-uk Kim
259e71b7053SJung-uk Kim ASN1_ITEM_start(UINT32)
260e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint32_pf, 0, "UINT32"
261e71b7053SJung-uk Kim ASN1_ITEM_end(UINT32)
262e71b7053SJung-uk Kim
263e71b7053SJung-uk Kim ASN1_ITEM_start(INT64)
264e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint64_pf,
265e71b7053SJung-uk Kim INTxx_FLAG_SIGNED, "INT64"
266e71b7053SJung-uk Kim ASN1_ITEM_end(INT64)
267e71b7053SJung-uk Kim
268e71b7053SJung-uk Kim ASN1_ITEM_start(UINT64)
269e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint64_pf, 0, "UINT64"
270e71b7053SJung-uk Kim ASN1_ITEM_end(UINT64)
271e71b7053SJung-uk Kim
272e71b7053SJung-uk Kim ASN1_ITEM_start(ZINT32)
273e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint32_pf,
274e71b7053SJung-uk Kim INTxx_FLAG_ZERO_DEFAULT|INTxx_FLAG_SIGNED, "ZINT32"
275e71b7053SJung-uk Kim ASN1_ITEM_end(ZINT32)
276e71b7053SJung-uk Kim
277e71b7053SJung-uk Kim ASN1_ITEM_start(ZUINT32)
278e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint32_pf,
279e71b7053SJung-uk Kim INTxx_FLAG_ZERO_DEFAULT, "ZUINT32"
280e71b7053SJung-uk Kim ASN1_ITEM_end(ZUINT32)
281e71b7053SJung-uk Kim
282e71b7053SJung-uk Kim ASN1_ITEM_start(ZINT64)
283e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint64_pf,
284e71b7053SJung-uk Kim INTxx_FLAG_ZERO_DEFAULT|INTxx_FLAG_SIGNED, "ZINT64"
285e71b7053SJung-uk Kim ASN1_ITEM_end(ZINT64)
286e71b7053SJung-uk Kim
287e71b7053SJung-uk Kim ASN1_ITEM_start(ZUINT64)
288e71b7053SJung-uk Kim ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &uint64_pf,
289e71b7053SJung-uk Kim INTxx_FLAG_ZERO_DEFAULT, "ZUINT64"
290e71b7053SJung-uk Kim ASN1_ITEM_end(ZUINT64)
291e71b7053SJung-uk Kim
292