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(<mp, 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, <mp, 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