x_long.c revision 325335
1/* x_long.c */
2/*
3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4 * 2000.
5 */
6/* ====================================================================
7 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in
18 *    the documentation and/or other materials provided with the
19 *    distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 *    software must display the following acknowledgment:
23 *    "This product includes software developed by the OpenSSL Project
24 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 *    endorse or promote products derived from this software without
28 *    prior written permission. For written permission, please contact
29 *    licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 *    nor may "OpenSSL" appear in their names without prior written
33 *    permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 *    acknowledgment:
37 *    "This product includes software developed by the OpenSSL Project
38 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com).  This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60#include <stdio.h>
61#include "cryptlib.h"
62#include <openssl/asn1t.h>
63#include <openssl/bn.h>
64
65/*
66 * Custom primitive type for long handling. This converts between an
67 * ASN1_INTEGER and a long directly.
68 */
69
70static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
71static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
72
73static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
74                    const ASN1_ITEM *it);
75static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
76                    int utype, char *free_cont, const ASN1_ITEM *it);
77static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
78                      int indent, const ASN1_PCTX *pctx);
79
80static ASN1_PRIMITIVE_FUNCS long_pf = {
81    NULL, 0,
82    long_new,
83    long_free,
84    long_free,                  /* Clear should set to initial value */
85    long_c2i,
86    long_i2c,
87    long_print
88};
89
90ASN1_ITEM_start(LONG)
91        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
92ASN1_ITEM_end(LONG)
93
94ASN1_ITEM_start(ZLONG)
95        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
96ASN1_ITEM_end(ZLONG)
97
98static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
99{
100    *(long *)pval = it->size;
101    return 1;
102}
103
104static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
105{
106    *(long *)pval = it->size;
107}
108
109static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
110                    const ASN1_ITEM *it)
111{
112    long ltmp;
113    unsigned long utmp;
114    int clen, pad, i;
115    /* this exists to bypass broken gcc optimization */
116    char *cp = (char *)pval;
117
118    /* use memcpy, because we may not be long aligned */
119    memcpy(&ltmp, cp, sizeof(long));
120
121    if (ltmp == it->size)
122        return -1;
123    /*
124     * Convert the long to positive: we subtract one if negative so we can
125     * cleanly handle the padding if only the MSB of the leading octet is
126     * set.
127     */
128    if (ltmp < 0)
129        utmp = 0 - (unsigned long)ltmp - 1;
130    else
131        utmp = ltmp;
132    clen = BN_num_bits_word(utmp);
133    /* If MSB of leading octet set we need to pad */
134    if (!(clen & 0x7))
135        pad = 1;
136    else
137        pad = 0;
138
139    /* Convert number of bits to number of octets */
140    clen = (clen + 7) >> 3;
141
142    if (cont) {
143        if (pad)
144            *cont++ = (ltmp < 0) ? 0xff : 0;
145        for (i = clen - 1; i >= 0; i--) {
146            cont[i] = (unsigned char)(utmp & 0xff);
147            if (ltmp < 0)
148                cont[i] ^= 0xff;
149            utmp >>= 8;
150        }
151    }
152    return clen + pad;
153}
154
155static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
156                    int utype, char *free_cont, const ASN1_ITEM *it)
157{
158    int neg = -1, i;
159    long ltmp;
160    unsigned long utmp = 0;
161    char *cp = (char *)pval;
162
163    if (len) {
164        /*
165         * Check possible pad byte.  Worst case, we're skipping past actual
166         * content, but since that's only with 0x00 and 0xff and we set neg
167         * accordingly, the result will be correct in the end anyway.
168         */
169        switch (cont[0]) {
170        case 0xff:
171            cont++;
172            len--;
173            neg = 1;
174            break;
175        case 0:
176            cont++;
177            len--;
178            neg = 0;
179            break;
180        }
181    }
182    if (len > (int)sizeof(long)) {
183        ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
184        return 0;
185    }
186    if (neg == -1) {
187        /* Is it negative? */
188        if (len && (cont[0] & 0x80))
189            neg = 1;
190        else
191            neg = 0;
192    }
193    utmp = 0;
194    for (i = 0; i < len; i++) {
195        utmp <<= 8;
196        if (neg)
197            utmp |= cont[i] ^ 0xff;
198        else
199            utmp |= cont[i];
200    }
201    ltmp = (long)utmp;
202    if (neg) {
203        ltmp = -ltmp;
204        ltmp--;
205    }
206    if (ltmp == it->size) {
207        ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
208        return 0;
209    }
210    memcpy(cp, &ltmp, sizeof(long));
211    return 1;
212}
213
214static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
215                      int indent, const ASN1_PCTX *pctx)
216{
217    return BIO_printf(out, "%ld\n", *(long *)pval);
218}
219