1 /* $OpenBSD: a_enum.c,v 1.21 2021/12/15 18:00:31 jsing Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <limits.h> 60 #include <stdio.h> 61 62 #include <openssl/asn1.h> 63 #include <openssl/bn.h> 64 #include <openssl/buffer.h> 65 #include <openssl/err.h> 66 67 /* 68 * Code for ENUMERATED type: identical to INTEGER apart from a different tag. 69 * for comments on encoding see a_int.c 70 */ 71 72 int 73 ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v) 74 { 75 int j, k; 76 unsigned int i; 77 unsigned char buf[sizeof(long) + 1]; 78 long d; 79 80 a->type = V_ASN1_ENUMERATED; 81 if (a->length < (int)(sizeof(long) + 1)) { 82 free(a->data); 83 a->data = calloc(1, sizeof(long) + 1); 84 } 85 if (a->data == NULL) { 86 ASN1error(ERR_R_MALLOC_FAILURE); 87 return (0); 88 } 89 d = v; 90 if (d < 0) { 91 d = -d; 92 a->type = V_ASN1_NEG_ENUMERATED; 93 } 94 95 for (i = 0; i < sizeof(long); i++) { 96 if (d == 0) 97 break; 98 buf[i] = (int)d & 0xff; 99 d >>= 8; 100 } 101 j = 0; 102 for (k = i - 1; k >= 0; k--) 103 a->data[j++] = buf[k]; 104 a->length = j; 105 return (1); 106 } 107 108 long 109 ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a) 110 { 111 int neg = 0, i; 112 unsigned long r = 0; 113 114 if (a == NULL) 115 return (0L); 116 i = a->type; 117 if (i == V_ASN1_NEG_ENUMERATED) 118 neg = 1; 119 else if (i != V_ASN1_ENUMERATED) 120 return -1; 121 122 if (a->length > (int)sizeof(long)) { 123 /* hmm... a bit ugly */ 124 return -1; 125 } 126 if (a->data == NULL) 127 return 0; 128 129 for (i = 0; i < a->length; i++) { 130 r <<= 8; 131 r |= (unsigned char)a->data[i]; 132 } 133 134 if (r > LONG_MAX) 135 return -1; 136 137 if (neg) 138 return -(long)r; 139 return (long)r; 140 } 141 142 ASN1_ENUMERATED * 143 BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai) 144 { 145 ASN1_ENUMERATED *ret; 146 int len, j; 147 148 if (ai == NULL) 149 ret = ASN1_ENUMERATED_new(); 150 else 151 ret = ai; 152 if (ret == NULL) { 153 ASN1error(ERR_R_NESTED_ASN1_ERROR); 154 goto err; 155 } 156 if (BN_is_negative(bn)) 157 ret->type = V_ASN1_NEG_ENUMERATED; 158 else 159 ret->type = V_ASN1_ENUMERATED; 160 j = BN_num_bits(bn); 161 len = ((j == 0) ? 0 : ((j / 8) + 1)); 162 if (ret->length < len + 4) { 163 unsigned char *new_data = realloc(ret->data, len + 4); 164 if (!new_data) { 165 ASN1error(ERR_R_MALLOC_FAILURE); 166 goto err; 167 } 168 ret->data = new_data; 169 } 170 ret->length = BN_bn2bin(bn, ret->data); 171 172 /* Correct zero case */ 173 if (!ret->length) { 174 ret->data[0] = 0; 175 ret->length = 1; 176 } 177 return (ret); 178 179 err: 180 if (ret != ai) 181 ASN1_ENUMERATED_free(ret); 182 return (NULL); 183 } 184 185 BIGNUM * 186 ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn) 187 { 188 BIGNUM *ret; 189 190 if ((ret = BN_bin2bn(ai->data, ai->length, bn)) == NULL) 191 ASN1error(ASN1_R_BN_LIB); 192 else if (ai->type == V_ASN1_NEG_ENUMERATED) 193 BN_set_negative(ret, 1); 194 return (ret); 195 } 196 197 /* Based on a_int.c: equivalent ENUMERATED functions */ 198 199 int 200 i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a) 201 { 202 int i, n = 0; 203 static const char h[] = "0123456789ABCDEF"; 204 char buf[2]; 205 206 if (a == NULL) 207 return (0); 208 209 if (a->length == 0) { 210 if (BIO_write(bp, "00", 2) != 2) 211 goto err; 212 n = 2; 213 } else { 214 for (i = 0; i < a->length; i++) { 215 if ((i != 0) && (i % 35 == 0)) { 216 if (BIO_write(bp, "\\\n", 2) != 2) 217 goto err; 218 n += 2; 219 } 220 buf[0] = h[((unsigned char)a->data[i] >> 4) & 0x0f]; 221 buf[1] = h[((unsigned char)a->data[i]) & 0x0f]; 222 if (BIO_write(bp, buf, 2) != 2) 223 goto err; 224 n += 2; 225 } 226 } 227 return (n); 228 229 err: 230 return (-1); 231 } 232 233 int 234 a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size) 235 { 236 int ret = 0; 237 int i, j,k, m,n, again, bufsize; 238 unsigned char *s = NULL, *sp; 239 unsigned char *bufp; 240 int first = 1; 241 size_t num = 0, slen = 0; 242 243 bs->type = V_ASN1_ENUMERATED; 244 245 bufsize = BIO_gets(bp, buf, size); 246 for (;;) { 247 if (bufsize < 1) 248 goto err_sl; 249 i = bufsize; 250 if (buf[i-1] == '\n') 251 buf[--i] = '\0'; 252 if (i == 0) 253 goto err_sl; 254 if (buf[i-1] == '\r') 255 buf[--i] = '\0'; 256 if (i == 0) 257 goto err_sl; 258 if (buf[i - 1] == '\\') { 259 i--; 260 again = 1; 261 } else 262 again = 0; 263 buf[i] = '\0'; 264 if (i < 2) 265 goto err_sl; 266 267 bufp = (unsigned char *)buf; 268 if (first) { 269 first = 0; 270 if ((bufp[0] == '0') && (buf[1] == '0')) { 271 bufp += 2; 272 i -= 2; 273 } 274 } 275 k = 0; 276 if (i % 2 != 0) { 277 ASN1error(ASN1_R_ODD_NUMBER_OF_CHARS); 278 goto err; 279 } 280 i /= 2; 281 if (num + i > slen) { 282 sp = realloc(s, num + i); 283 if (sp == NULL) { 284 ASN1error(ERR_R_MALLOC_FAILURE); 285 goto err; 286 } 287 s = sp; 288 slen = num + i; 289 } 290 for (j = 0; j < i; j++, k += 2) { 291 for (n = 0; n < 2; n++) { 292 m = bufp[k + n]; 293 if ((m >= '0') && (m <= '9')) 294 m -= '0'; 295 else if ((m >= 'a') && (m <= 'f')) 296 m = m - 'a' + 10; 297 else if ((m >= 'A') && (m <= 'F')) 298 m = m - 'A' + 10; 299 else { 300 ASN1error(ASN1_R_NON_HEX_CHARACTERS); 301 goto err; 302 } 303 s[num + j] <<= 4; 304 s[num + j] |= m; 305 } 306 } 307 num += i; 308 if (again) 309 bufsize = BIO_gets(bp, buf, size); 310 else 311 break; 312 } 313 bs->length = num; 314 bs->data = s; 315 return (1); 316 317 err_sl: 318 ASN1error(ASN1_R_SHORT_LINE); 319 err: 320 free(s); 321 return (ret); 322 } 323