1109998Smarkm/* x_long.c */
2280297Sjkim/*
3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280297Sjkim * 2000.
5109998Smarkm */
6109998Smarkm/* ====================================================================
7109998Smarkm * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
8109998Smarkm *
9109998Smarkm * Redistribution and use in source and binary forms, with or without
10109998Smarkm * modification, are permitted provided that the following conditions
11109998Smarkm * are met:
12109998Smarkm *
13109998Smarkm * 1. Redistributions of source code must retain the above copyright
14280297Sjkim *    notice, this list of conditions and the following disclaimer.
15109998Smarkm *
16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
17109998Smarkm *    notice, this list of conditions and the following disclaimer in
18109998Smarkm *    the documentation and/or other materials provided with the
19109998Smarkm *    distribution.
20109998Smarkm *
21109998Smarkm * 3. All advertising materials mentioning features or use of this
22109998Smarkm *    software must display the following acknowledgment:
23109998Smarkm *    "This product includes software developed by the OpenSSL Project
24109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25109998Smarkm *
26109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27109998Smarkm *    endorse or promote products derived from this software without
28109998Smarkm *    prior written permission. For written permission, please contact
29109998Smarkm *    licensing@OpenSSL.org.
30109998Smarkm *
31109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
32109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
33109998Smarkm *    permission of the OpenSSL Project.
34109998Smarkm *
35109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
36109998Smarkm *    acknowledgment:
37109998Smarkm *    "This product includes software developed by the OpenSSL Project
38109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39109998Smarkm *
40109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
52109998Smarkm * ====================================================================
53109998Smarkm *
54109998Smarkm * This product includes cryptographic software written by Eric Young
55109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
56109998Smarkm * Hudson (tjh@cryptsoft.com).
57109998Smarkm *
58109998Smarkm */
59109998Smarkm
60109998Smarkm#include <stdio.h>
61109998Smarkm#include "cryptlib.h"
62109998Smarkm#include <openssl/asn1t.h>
63160814Ssimon#include <openssl/bn.h>
64109998Smarkm
65280297Sjkim/*
66280297Sjkim * Custom primitive type for long handling. This converts between an
67280297Sjkim * ASN1_INTEGER and a long directly.
68109998Smarkm */
69109998Smarkm
70109998Smarkmstatic int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
71109998Smarkmstatic void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
72109998Smarkm
73280297Sjkimstatic int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
74280297Sjkim                    const ASN1_ITEM *it);
75280297Sjkimstatic int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
76280297Sjkim                    int utype, char *free_cont, const ASN1_ITEM *it);
77280297Sjkimstatic int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
78280297Sjkim                      int indent, const ASN1_PCTX *pctx);
79109998Smarkm
80109998Smarkmstatic ASN1_PRIMITIVE_FUNCS long_pf = {
81280297Sjkim    NULL, 0,
82280297Sjkim    long_new,
83280297Sjkim    long_free,
84280297Sjkim    long_free,                  /* Clear should set to initial value */
85280297Sjkim    long_c2i,
86280297Sjkim    long_i2c,
87280297Sjkim    long_print
88109998Smarkm};
89109998Smarkm
90109998SmarkmASN1_ITEM_start(LONG)
91280297Sjkim        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
92109998SmarkmASN1_ITEM_end(LONG)
93109998Smarkm
94109998SmarkmASN1_ITEM_start(ZLONG)
95280297Sjkim        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
96109998SmarkmASN1_ITEM_end(ZLONG)
97109998Smarkm
98109998Smarkmstatic int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
99109998Smarkm{
100280297Sjkim    *(long *)pval = it->size;
101280297Sjkim    return 1;
102109998Smarkm}
103109998Smarkm
104109998Smarkmstatic void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
105109998Smarkm{
106280297Sjkim    *(long *)pval = it->size;
107109998Smarkm}
108109998Smarkm
109280297Sjkimstatic int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
110280297Sjkim                    const ASN1_ITEM *it)
111109998Smarkm{
112280297Sjkim    long ltmp;
113280297Sjkim    unsigned long utmp;
114280297Sjkim    int clen, pad, i;
115280297Sjkim    /* this exists to bypass broken gcc optimization */
116280297Sjkim    char *cp = (char *)pval;
117127128Snectar
118280297Sjkim    /* use memcpy, because we may not be long aligned */
119280297Sjkim    memcpy(&ltmp, cp, sizeof(long));
120127128Snectar
121280297Sjkim    if (ltmp == it->size)
122280297Sjkim        return -1;
123280297Sjkim    /*
124280297Sjkim     * Convert the long to positive: we subtract one if negative so we can
125280297Sjkim     * cleanly handle the padding if only the MSB of the leading octet is
126280297Sjkim     * set.
127280297Sjkim     */
128280297Sjkim    if (ltmp < 0)
129325335Sjkim        utmp = 0 - (unsigned long)ltmp - 1;
130280297Sjkim    else
131280297Sjkim        utmp = ltmp;
132280297Sjkim    clen = BN_num_bits_word(utmp);
133280297Sjkim    /* If MSB of leading octet set we need to pad */
134280297Sjkim    if (!(clen & 0x7))
135280297Sjkim        pad = 1;
136280297Sjkim    else
137280297Sjkim        pad = 0;
138109998Smarkm
139280297Sjkim    /* Convert number of bits to number of octets */
140280297Sjkim    clen = (clen + 7) >> 3;
141109998Smarkm
142280297Sjkim    if (cont) {
143280297Sjkim        if (pad)
144280297Sjkim            *cont++ = (ltmp < 0) ? 0xff : 0;
145280297Sjkim        for (i = clen - 1; i >= 0; i--) {
146280297Sjkim            cont[i] = (unsigned char)(utmp & 0xff);
147280297Sjkim            if (ltmp < 0)
148280297Sjkim                cont[i] ^= 0xff;
149280297Sjkim            utmp >>= 8;
150280297Sjkim        }
151280297Sjkim    }
152280297Sjkim    return clen + pad;
153109998Smarkm}
154109998Smarkm
155160814Ssimonstatic int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
156280297Sjkim                    int utype, char *free_cont, const ASN1_ITEM *it)
157109998Smarkm{
158325335Sjkim    int neg = -1, i;
159280297Sjkim    long ltmp;
160280297Sjkim    unsigned long utmp = 0;
161280297Sjkim    char *cp = (char *)pval;
162325335Sjkim
163325335Sjkim    if (len) {
164325335Sjkim        /*
165325335Sjkim         * Check possible pad byte.  Worst case, we're skipping past actual
166325335Sjkim         * content, but since that's only with 0x00 and 0xff and we set neg
167325335Sjkim         * accordingly, the result will be correct in the end anyway.
168325335Sjkim         */
169325335Sjkim        switch (cont[0]) {
170325335Sjkim        case 0xff:
171325335Sjkim            cont++;
172325335Sjkim            len--;
173325335Sjkim            neg = 1;
174325335Sjkim            break;
175325335Sjkim        case 0:
176325335Sjkim            cont++;
177325335Sjkim            len--;
178325335Sjkim            neg = 0;
179325335Sjkim            break;
180325335Sjkim        }
181325335Sjkim    }
182280297Sjkim    if (len > (int)sizeof(long)) {
183280297Sjkim        ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
184280297Sjkim        return 0;
185280297Sjkim    }
186325335Sjkim    if (neg == -1) {
187325335Sjkim        /* Is it negative? */
188325335Sjkim        if (len && (cont[0] & 0x80))
189325335Sjkim            neg = 1;
190325335Sjkim        else
191325335Sjkim            neg = 0;
192325335Sjkim    }
193280297Sjkim    utmp = 0;
194280297Sjkim    for (i = 0; i < len; i++) {
195280297Sjkim        utmp <<= 8;
196280297Sjkim        if (neg)
197280297Sjkim            utmp |= cont[i] ^ 0xff;
198280297Sjkim        else
199280297Sjkim            utmp |= cont[i];
200280297Sjkim    }
201280297Sjkim    ltmp = (long)utmp;
202280297Sjkim    if (neg) {
203280297Sjkim        ltmp = -ltmp;
204325335Sjkim        ltmp--;
205280297Sjkim    }
206280297Sjkim    if (ltmp == it->size) {
207280297Sjkim        ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
208280297Sjkim        return 0;
209280297Sjkim    }
210280297Sjkim    memcpy(cp, &ltmp, sizeof(long));
211280297Sjkim    return 1;
212109998Smarkm}
213238405Sjkim
214238405Sjkimstatic int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
215280297Sjkim                      int indent, const ASN1_PCTX *pctx)
216280297Sjkim{
217280297Sjkim    return BIO_printf(out, "%ld\n", *(long *)pval);
218280297Sjkim}
219