1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdio.h>
11e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
12e1051a39Sopenharmony_ci#include <openssl/asn1t.h>
13e1051a39Sopenharmony_ci
14e1051a39Sopenharmony_ci#define COPY_SIZE(a, b) (sizeof(a) < sizeof(b) ? sizeof(a) : sizeof(b))
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci/*
17e1051a39Sopenharmony_ci * Custom primitive type for long handling. This converts between an
18e1051a39Sopenharmony_ci * ASN1_INTEGER and a long directly.
19e1051a39Sopenharmony_ci */
20e1051a39Sopenharmony_ci
21e1051a39Sopenharmony_cistatic int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
22e1051a39Sopenharmony_cistatic void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_cistatic int long_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
25e1051a39Sopenharmony_ci                    const ASN1_ITEM *it);
26e1051a39Sopenharmony_cistatic int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
27e1051a39Sopenharmony_ci                    int utype, char *free_cont, const ASN1_ITEM *it);
28e1051a39Sopenharmony_cistatic int long_print(BIO *out, const ASN1_VALUE **pval, const ASN1_ITEM *it,
29e1051a39Sopenharmony_ci                      int indent, const ASN1_PCTX *pctx);
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_cistatic ASN1_PRIMITIVE_FUNCS long_pf = {
32e1051a39Sopenharmony_ci    NULL, 0,
33e1051a39Sopenharmony_ci    long_new,
34e1051a39Sopenharmony_ci    long_free,
35e1051a39Sopenharmony_ci    long_free,                  /* Clear should set to initial value */
36e1051a39Sopenharmony_ci    long_c2i,
37e1051a39Sopenharmony_ci    long_i2c,
38e1051a39Sopenharmony_ci    long_print
39e1051a39Sopenharmony_ci};
40e1051a39Sopenharmony_ci
41e1051a39Sopenharmony_ciASN1_ITEM_start(LONG)
42e1051a39Sopenharmony_ci        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
43e1051a39Sopenharmony_ciASN1_ITEM_end(LONG)
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_ciASN1_ITEM_start(ZLONG)
46e1051a39Sopenharmony_ci        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
47e1051a39Sopenharmony_ciASN1_ITEM_end(ZLONG)
48e1051a39Sopenharmony_ci
49e1051a39Sopenharmony_cistatic int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
50e1051a39Sopenharmony_ci{
51e1051a39Sopenharmony_ci    memcpy(pval, &it->size, COPY_SIZE(*pval, it->size));
52e1051a39Sopenharmony_ci    return 1;
53e1051a39Sopenharmony_ci}
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_cistatic void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
56e1051a39Sopenharmony_ci{
57e1051a39Sopenharmony_ci    memcpy(pval, &it->size, COPY_SIZE(*pval, it->size));
58e1051a39Sopenharmony_ci}
59e1051a39Sopenharmony_ci
60e1051a39Sopenharmony_ci/*
61e1051a39Sopenharmony_ci * Originally BN_num_bits_word was called to perform this operation, but
62e1051a39Sopenharmony_ci * trouble is that there is no guarantee that sizeof(long) equals to
63e1051a39Sopenharmony_ci * sizeof(BN_ULONG). BN_ULONG is a configurable type that can be as wide
64e1051a39Sopenharmony_ci * as long, but also double or half...
65e1051a39Sopenharmony_ci */
66e1051a39Sopenharmony_cistatic int num_bits_ulong(unsigned long value)
67e1051a39Sopenharmony_ci{
68e1051a39Sopenharmony_ci    size_t i;
69e1051a39Sopenharmony_ci    unsigned long ret = 0;
70e1051a39Sopenharmony_ci
71e1051a39Sopenharmony_ci    /*
72e1051a39Sopenharmony_ci     * It is argued that *on average* constant counter loop performs
73e1051a39Sopenharmony_ci     * not worse [if not better] than one with conditional break or
74e1051a39Sopenharmony_ci     * mask-n-table-lookup-style, because of branch misprediction
75e1051a39Sopenharmony_ci     * penalties.
76e1051a39Sopenharmony_ci     */
77e1051a39Sopenharmony_ci    for (i = 0; i < sizeof(value) * 8; i++) {
78e1051a39Sopenharmony_ci        ret += (value != 0);
79e1051a39Sopenharmony_ci        value >>= 1;
80e1051a39Sopenharmony_ci    }
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_ci    return (int)ret;
83e1051a39Sopenharmony_ci}
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_cistatic int long_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
86e1051a39Sopenharmony_ci                    const ASN1_ITEM *it)
87e1051a39Sopenharmony_ci{
88e1051a39Sopenharmony_ci    long ltmp;
89e1051a39Sopenharmony_ci    unsigned long utmp, sign;
90e1051a39Sopenharmony_ci    int clen, pad, i;
91e1051a39Sopenharmony_ci
92e1051a39Sopenharmony_ci    memcpy(&ltmp, pval, COPY_SIZE(*pval, ltmp));
93e1051a39Sopenharmony_ci    if (ltmp == it->size)
94e1051a39Sopenharmony_ci        return -1;
95e1051a39Sopenharmony_ci    /*
96e1051a39Sopenharmony_ci     * Convert the long to positive: we subtract one if negative so we can
97e1051a39Sopenharmony_ci     * cleanly handle the padding if only the MSB of the leading octet is
98e1051a39Sopenharmony_ci     * set.
99e1051a39Sopenharmony_ci     */
100e1051a39Sopenharmony_ci    if (ltmp < 0) {
101e1051a39Sopenharmony_ci        sign = 0xff;
102e1051a39Sopenharmony_ci        utmp = 0 - (unsigned long)ltmp - 1;
103e1051a39Sopenharmony_ci    } else {
104e1051a39Sopenharmony_ci        sign = 0;
105e1051a39Sopenharmony_ci        utmp = ltmp;
106e1051a39Sopenharmony_ci    }
107e1051a39Sopenharmony_ci    clen = num_bits_ulong(utmp);
108e1051a39Sopenharmony_ci    /* If MSB of leading octet set we need to pad */
109e1051a39Sopenharmony_ci    if (!(clen & 0x7))
110e1051a39Sopenharmony_ci        pad = 1;
111e1051a39Sopenharmony_ci    else
112e1051a39Sopenharmony_ci        pad = 0;
113e1051a39Sopenharmony_ci
114e1051a39Sopenharmony_ci    /* Convert number of bits to number of octets */
115e1051a39Sopenharmony_ci    clen = (clen + 7) >> 3;
116e1051a39Sopenharmony_ci
117e1051a39Sopenharmony_ci    if (cont != NULL) {
118e1051a39Sopenharmony_ci        if (pad)
119e1051a39Sopenharmony_ci            *cont++ = (unsigned char)sign;
120e1051a39Sopenharmony_ci        for (i = clen - 1; i >= 0; i--) {
121e1051a39Sopenharmony_ci            cont[i] = (unsigned char)(utmp ^ sign);
122e1051a39Sopenharmony_ci            utmp >>= 8;
123e1051a39Sopenharmony_ci        }
124e1051a39Sopenharmony_ci    }
125e1051a39Sopenharmony_ci    return clen + pad;
126e1051a39Sopenharmony_ci}
127e1051a39Sopenharmony_ci
128e1051a39Sopenharmony_cistatic int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
129e1051a39Sopenharmony_ci                    int utype, char *free_cont, const ASN1_ITEM *it)
130e1051a39Sopenharmony_ci{
131e1051a39Sopenharmony_ci    int i;
132e1051a39Sopenharmony_ci    long ltmp;
133e1051a39Sopenharmony_ci    unsigned long utmp = 0, sign = 0x100;
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_ci    if (len > 1) {
136e1051a39Sopenharmony_ci        /*
137e1051a39Sopenharmony_ci         * Check possible pad byte.  Worst case, we're skipping past actual
138e1051a39Sopenharmony_ci         * content, but since that's only with 0x00 and 0xff and we set neg
139e1051a39Sopenharmony_ci         * accordingly, the result will be correct in the end anyway.
140e1051a39Sopenharmony_ci         */
141e1051a39Sopenharmony_ci        switch (cont[0]) {
142e1051a39Sopenharmony_ci        case 0xff:
143e1051a39Sopenharmony_ci            cont++;
144e1051a39Sopenharmony_ci            len--;
145e1051a39Sopenharmony_ci            sign = 0xff;
146e1051a39Sopenharmony_ci            break;
147e1051a39Sopenharmony_ci        case 0:
148e1051a39Sopenharmony_ci            cont++;
149e1051a39Sopenharmony_ci            len--;
150e1051a39Sopenharmony_ci            sign = 0;
151e1051a39Sopenharmony_ci            break;
152e1051a39Sopenharmony_ci        }
153e1051a39Sopenharmony_ci    }
154e1051a39Sopenharmony_ci    if (len > (int)sizeof(long)) {
155e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
156e1051a39Sopenharmony_ci        return 0;
157e1051a39Sopenharmony_ci    }
158e1051a39Sopenharmony_ci
159e1051a39Sopenharmony_ci    if (sign == 0x100) {
160e1051a39Sopenharmony_ci        /* Is it negative? */
161e1051a39Sopenharmony_ci        if (len && (cont[0] & 0x80))
162e1051a39Sopenharmony_ci            sign = 0xff;
163e1051a39Sopenharmony_ci        else
164e1051a39Sopenharmony_ci            sign = 0;
165e1051a39Sopenharmony_ci    } else if (((sign ^ cont[0]) & 0x80) == 0) { /* same sign bit? */
166e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_PADDING);
167e1051a39Sopenharmony_ci        return 0;
168e1051a39Sopenharmony_ci    }
169e1051a39Sopenharmony_ci    utmp = 0;
170e1051a39Sopenharmony_ci    for (i = 0; i < len; i++) {
171e1051a39Sopenharmony_ci        utmp <<= 8;
172e1051a39Sopenharmony_ci        utmp |= cont[i] ^ sign;
173e1051a39Sopenharmony_ci    }
174e1051a39Sopenharmony_ci    ltmp = (long)utmp;
175e1051a39Sopenharmony_ci    if (ltmp < 0) {
176e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
177e1051a39Sopenharmony_ci        return 0;
178e1051a39Sopenharmony_ci    }
179e1051a39Sopenharmony_ci    if (sign)
180e1051a39Sopenharmony_ci        ltmp = -ltmp - 1;
181e1051a39Sopenharmony_ci    if (ltmp == it->size) {
182e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
183e1051a39Sopenharmony_ci        return 0;
184e1051a39Sopenharmony_ci    }
185e1051a39Sopenharmony_ci    memcpy(pval, &ltmp, COPY_SIZE(*pval, ltmp));
186e1051a39Sopenharmony_ci    return 1;
187e1051a39Sopenharmony_ci}
188e1051a39Sopenharmony_ci
189e1051a39Sopenharmony_cistatic int long_print(BIO *out, const ASN1_VALUE **pval, const ASN1_ITEM *it,
190e1051a39Sopenharmony_ci                      int indent, const ASN1_PCTX *pctx)
191e1051a39Sopenharmony_ci{
192e1051a39Sopenharmony_ci    long l;
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_ci    memcpy(&l, pval, COPY_SIZE(*pval, l));
195e1051a39Sopenharmony_ci    return BIO_printf(out, "%ld\n", l);
196e1051a39Sopenharmony_ci}
197