diff options
author | jsing <> | 2022-07-02 18:14:35 +0000 |
---|---|---|
committer | jsing <> | 2022-07-02 18:14:35 +0000 |
commit | 963c47667fc47c301ad45580a2b27b25cf2a3c6d (patch) | |
tree | 6a96b8dcfddfc28019de4d09fe4a3134a64141df | |
parent | 7ef5c3d971675518039445a2bb528972218e01b2 (diff) | |
download | openbsd-963c47667fc47c301ad45580a2b27b25cf2a3c6d.tar.gz openbsd-963c47667fc47c301ad45580a2b27b25cf2a3c6d.tar.bz2 openbsd-963c47667fc47c301ad45580a2b27b25cf2a3c6d.zip |
Use ASN1_INTEGER to parse/build (Z)LONG_it
Rather than having yet another (broken) ASN.1 INTEGER content builder and
parser, use {c2i,i2c}_ASN1_INTEGER().
ok beck@
-rw-r--r-- | src/lib/libcrypto/asn1/x_long.c | 136 |
1 files changed, 67 insertions, 69 deletions
diff --git a/src/lib/libcrypto/asn1/x_long.c b/src/lib/libcrypto/asn1/x_long.c index b51ea6f214..543c56a5b2 100644 --- a/src/lib/libcrypto/asn1/x_long.c +++ b/src/lib/libcrypto/asn1/x_long.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x_long.c,v 1.17 2022/06/26 13:10:15 jsing Exp $ */ | 1 | /* $OpenBSD: x_long.c,v 1.18 2022/07/02 18:14:35 jsing Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 2000. | 3 | * project 2000. |
4 | */ | 4 | */ |
@@ -56,13 +56,15 @@ | |||
56 | * | 56 | * |
57 | */ | 57 | */ |
58 | 58 | ||
59 | #include <stdio.h> | 59 | #include <limits.h> |
60 | #include <string.h> | 60 | #include <string.h> |
61 | 61 | ||
62 | #include <openssl/asn1t.h> | 62 | #include <openssl/asn1t.h> |
63 | #include <openssl/bn.h> | 63 | #include <openssl/bn.h> |
64 | #include <openssl/err.h> | 64 | #include <openssl/err.h> |
65 | 65 | ||
66 | #include "asn1_locl.h" | ||
67 | |||
66 | /* | 68 | /* |
67 | * Custom primitive type for long handling. This converts between an | 69 | * Custom primitive type for long handling. This converts between an |
68 | * ASN1_INTEGER and a long directly. | 70 | * ASN1_INTEGER and a long directly. |
@@ -72,10 +74,10 @@ static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it); | |||
72 | static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it); | 74 | static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it); |
73 | static void long_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); | 75 | static void long_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); |
74 | 76 | ||
75 | static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, | 77 | static int long_i2c(ASN1_VALUE **pval, unsigned char *content, int *putype, |
76 | const ASN1_ITEM *it); | 78 | const ASN1_ITEM *it); |
77 | static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, | 79 | static int long_c2i(ASN1_VALUE **pval, const unsigned char *content, int len, |
78 | int utype, char *free_cont, const ASN1_ITEM *it); | 80 | int utype, char *free_content, const ASN1_ITEM *it); |
79 | static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, | 81 | static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, |
80 | int indent, const ASN1_PCTX *pctx); | 82 | int indent, const ASN1_PCTX *pctx); |
81 | 83 | ||
@@ -144,86 +146,82 @@ long_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) | |||
144 | } | 146 | } |
145 | 147 | ||
146 | static int | 148 | static int |
147 | long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, | 149 | long_i2c(ASN1_VALUE **pval, unsigned char *content, int *putype, |
148 | const ASN1_ITEM *it) | 150 | const ASN1_ITEM *it) |
149 | { | 151 | { |
150 | long ltmp; | 152 | ASN1_INTEGER *aint; |
151 | unsigned long utmp; | 153 | uint8_t **pp = NULL; |
152 | int clen, pad, i; | 154 | long val; |
155 | int ret = 0; | ||
153 | 156 | ||
154 | long_get(pval, <mp); | 157 | long_get(pval, &val); |
155 | 158 | ||
156 | if (ltmp == it->size) | 159 | /* |
157 | return -1; | 160 | * The zero value for this type (stored in the overloaded it->size |
158 | /* Convert the long to positive: we subtract one if negative so | 161 | * field) is considered to be invalid. |
159 | * we can cleanly handle the padding if only the MSB of the leading | ||
160 | * octet is set. | ||
161 | */ | 162 | */ |
162 | if (ltmp < 0) | 163 | if (val == it->size) |
163 | utmp = -(ltmp + 1); | 164 | return -1; |
164 | else | 165 | |
165 | utmp = ltmp; | 166 | if ((aint = ASN1_INTEGER_new()) == NULL) |
166 | clen = BN_num_bits_word(utmp); | 167 | goto err; |
167 | /* If MSB of leading octet set we need to pad */ | 168 | if (!ASN1_INTEGER_set_int64(aint, (int64_t)val)) |
168 | if (!(clen & 0x7)) | 169 | goto err; |
169 | pad = 1; | 170 | if (content != NULL) |
170 | else | 171 | pp = &content; |
171 | pad = 0; | 172 | ret = i2c_ASN1_INTEGER(aint, pp); |
172 | 173 | ||
173 | /* Convert number of bits to number of octets */ | 174 | err: |
174 | clen = (clen + 7) >> 3; | 175 | ASN1_INTEGER_free(aint); |
175 | 176 | ||
176 | if (cont) { | 177 | return ret; |
177 | if (pad) | ||
178 | *cont++ = (ltmp < 0) ? 0xff : 0; | ||
179 | for (i = clen - 1; i >= 0; i--) { | ||
180 | cont[i] = (unsigned char)(utmp & 0xff); | ||
181 | if (ltmp < 0) | ||
182 | cont[i] ^= 0xff; | ||
183 | utmp >>= 8; | ||
184 | } | ||
185 | } | ||
186 | return clen + pad; | ||
187 | } | 178 | } |
188 | 179 | ||
189 | static int | 180 | static int |
190 | long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, | 181 | long_c2i(ASN1_VALUE **pval, const unsigned char *content, int len, int utype, |
191 | char *free_cont, const ASN1_ITEM *it) | 182 | char *free_content, const ASN1_ITEM *it) |
192 | { | 183 | { |
193 | int neg, i; | 184 | ASN1_INTEGER *aint = NULL; |
194 | long ltmp; | 185 | const uint8_t **pp = NULL; |
195 | unsigned long utmp = 0; | 186 | int64_t val = 0; |
187 | int ret = 0; | ||
188 | |||
189 | /* | ||
190 | * The original long_i2c() mishandled 0 values and encoded them as | ||
191 | * content with zero length, rather than a single zero byte. Permit | ||
192 | * zero length content here for backwards compatibility. | ||
193 | */ | ||
194 | if (len != 0) { | ||
195 | if (content != NULL) | ||
196 | pp = &content; | ||
197 | if (!c2i_ASN1_INTEGER(&aint, pp, len)) | ||
198 | goto err; | ||
199 | if (!ASN1_INTEGER_get_int64(&val, aint)) | ||
200 | goto err; | ||
201 | } | ||
196 | 202 | ||
197 | if (len > (int)sizeof(long)) { | 203 | if (val < LONG_MIN || val > LONG_MAX) { |
198 | ASN1error(ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); | 204 | ASN1error(ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); |
199 | return 0; | 205 | goto err; |
200 | } | ||
201 | /* Is it negative? */ | ||
202 | if (len && (cont[0] & 0x80)) | ||
203 | neg = 1; | ||
204 | else | ||
205 | neg = 0; | ||
206 | utmp = 0; | ||
207 | for (i = 0; i < len; i++) { | ||
208 | utmp <<= 8; | ||
209 | if (neg) | ||
210 | utmp |= cont[i] ^ 0xff; | ||
211 | else | ||
212 | utmp |= cont[i]; | ||
213 | } | 206 | } |
214 | ltmp = (long)utmp; | 207 | |
215 | if (neg) { | 208 | /* |
216 | ltmp = -ltmp; | 209 | * The zero value for this type (stored in the overloaded it->size |
217 | ltmp--; | 210 | * field) is considered to be invalid. |
218 | } | 211 | */ |
219 | if (ltmp == it->size) { | 212 | if (val == (int64_t)it->size) { |
220 | ASN1error(ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); | 213 | ASN1error(ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); |
221 | return 0; | 214 | goto err; |
222 | } | 215 | } |
223 | 216 | ||
224 | long_set(pval, ltmp); | 217 | long_set(pval, (long)val); |
225 | 218 | ||
226 | return 1; | 219 | ret = 1; |
220 | |||
221 | err: | ||
222 | ASN1_INTEGER_free(aint); | ||
223 | |||
224 | return ret; | ||
227 | } | 225 | } |
228 | 226 | ||
229 | static int | 227 | static int |