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