]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
2039c421 | 2 | * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. |
e76f935e | 3 | * |
2039c421 RS |
4 | * Licensed under the OpenSSL license (the "License"). You may not use |
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> |
0f814687 | 13 | #include <openssl/bn.h> |
e76f935e | 14 | |
0f113f3e MC |
15 | /* |
16 | * Custom primitive type for long handling. This converts between an | |
17 | * ASN1_INTEGER and a long directly. | |
e76f935e DSH |
18 | */ |
19 | ||
9d6b1ce6 DSH |
20 | static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it); |
21 | static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it); | |
e76f935e | 22 | |
0f113f3e MC |
23 | static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, |
24 | const ASN1_ITEM *it); | |
25 | static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, | |
26 | int utype, char *free_cont, const ASN1_ITEM *it); | |
27 | static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, | |
28 | int indent, const ASN1_PCTX *pctx); | |
e76f935e | 29 | |
9d6b1ce6 | 30 | static ASN1_PRIMITIVE_FUNCS long_pf = { |
0f113f3e MC |
31 | NULL, 0, |
32 | long_new, | |
33 | long_free, | |
34 | long_free, /* Clear should set to initial value */ | |
35 | long_c2i, | |
36 | long_i2c, | |
37 | long_print | |
9d6b1ce6 | 38 | }; |
e76f935e | 39 | |
bb5ea36b | 40 | ASN1_ITEM_start(LONG) |
0f113f3e | 41 | ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG" |
d339187b | 42 | ASN1_ITEM_end(LONG) |
bb5ea36b DSH |
43 | |
44 | ASN1_ITEM_start(ZLONG) | |
0f113f3e | 45 | ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG" |
d339187b | 46 | ASN1_ITEM_end(ZLONG) |
e76f935e | 47 | |
9d6b1ce6 | 48 | static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it) |
e76f935e | 49 | { |
437b14b5 DSH |
50 | *(long *)pval = it->size; |
51 | return 1; | |
e76f935e DSH |
52 | } |
53 | ||
9d6b1ce6 | 54 | static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it) |
e76f935e | 55 | { |
437b14b5 | 56 | *(long *)pval = it->size; |
9d6b1ce6 DSH |
57 | } |
58 | ||
437b14b5 DSH |
59 | static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, |
60 | const ASN1_ITEM *it) | |
9d6b1ce6 | 61 | { |
437b14b5 DSH |
62 | long ltmp; |
63 | unsigned long utmp; | |
64 | int clen, pad, i; | |
65 | /* this exists to bypass broken gcc optimization */ | |
66 | char *cp = (char *)pval; | |
67 | ||
68 | /* use memcpy, because we may not be long aligned */ | |
69 | memcpy(<mp, cp, sizeof(long)); | |
70 | ||
71 | if (ltmp == it->size) | |
72 | return -1; | |
73 | /* | |
74 | * Convert the long to positive: we subtract one if negative so we can | |
75 | * cleanly handle the padding if only the MSB of the leading octet is | |
76 | * set. | |
77 | */ | |
78 | if (ltmp < 0) | |
68d4bcfd | 79 | utmp = 0 - (unsigned long)ltmp - 1; |
437b14b5 DSH |
80 | else |
81 | utmp = ltmp; | |
82 | clen = BN_num_bits_word(utmp); | |
83 | /* If MSB of leading octet set we need to pad */ | |
84 | if (!(clen & 0x7)) | |
85 | pad = 1; | |
86 | else | |
87 | pad = 0; | |
88 | ||
89 | /* Convert number of bits to number of octets */ | |
90 | clen = (clen + 7) >> 3; | |
91 | ||
92 | if (cont) { | |
93 | if (pad) | |
94 | *cont++ = (ltmp < 0) ? 0xff : 0; | |
95 | for (i = clen - 1; i >= 0; i--) { | |
96 | cont[i] = (unsigned char)(utmp & 0xff); | |
97 | if (ltmp < 0) | |
98 | cont[i] ^= 0xff; | |
99 | utmp >>= 8; | |
0f113f3e | 100 | } |
437b14b5 DSH |
101 | } |
102 | return clen + pad; | |
9d6b1ce6 DSH |
103 | } |
104 | ||
875a644a | 105 | static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
0f113f3e | 106 | int utype, char *free_cont, const ASN1_ITEM *it) |
9d6b1ce6 | 107 | { |
437b14b5 DSH |
108 | int neg, i; |
109 | long ltmp; | |
110 | unsigned long utmp = 0; | |
111 | char *cp = (char *)pval; | |
112 | if (len > (int)sizeof(long)) { | |
113 | ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); | |
114 | return 0; | |
115 | } | |
116 | /* Is it negative? */ | |
117 | if (len && (cont[0] & 0x80)) | |
118 | neg = 1; | |
119 | else | |
120 | neg = 0; | |
121 | utmp = 0; | |
122 | for (i = 0; i < len; i++) { | |
123 | utmp <<= 8; | |
124 | if (neg) | |
125 | utmp |= cont[i] ^ 0xff; | |
126 | else | |
127 | utmp |= cont[i]; | |
128 | } | |
129 | ltmp = (long)utmp; | |
130 | if (neg) { | |
437b14b5 | 131 | ltmp = -ltmp; |
5bea15eb | 132 | ltmp--; |
437b14b5 DSH |
133 | } |
134 | if (ltmp == it->size) { | |
135 | ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); | |
136 | return 0; | |
137 | } | |
138 | memcpy(cp, <mp, sizeof(long)); | |
139 | return 1; | |
e76f935e | 140 | } |
9e5df8e4 DSH |
141 | |
142 | static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, | |
437b14b5 DSH |
143 | int indent, const ASN1_PCTX *pctx) |
144 | { | |
145 | return BIO_printf(out, "%ld\n", *(long *)pval); | |
146 | } |