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