asn1_lib.c revision 109998
148156Sjlemon/* crypto/asn1/asn1_lib.c */ 257828Sjlemon/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 348156Sjlemon * All rights reserved. 448156Sjlemon * 548156Sjlemon * This package is an SSL implementation written 648156Sjlemon * by Eric Young (eay@cryptsoft.com). 748156Sjlemon * The implementation was written so as to conform with Netscapes SSL. 848156Sjlemon * 948156Sjlemon * This library is free for commercial and non-commercial use as long as 1048156Sjlemon * the following conditions are aheared to. The following conditions 1148156Sjlemon * apply to all code found in this distribution, be it the RC4, RSA, 1248156Sjlemon * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1348156Sjlemon * included with this distribution is covered by the same copyright terms 1448156Sjlemon * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1548156Sjlemon * 1648156Sjlemon * Copyright remains Eric Young's, and as such any Copyright notices in 1748156Sjlemon * the code are not to be removed. 1848156Sjlemon * If this package is used in a product, Eric Young should be given attribution 1948156Sjlemon * as the author of the parts of the library used. 2048156Sjlemon * This can be in the form of a textual message at program startup or 2148156Sjlemon * in documentation (online or textual) provided with the package. 2248156Sjlemon * 2348156Sjlemon * Redistribution and use in source and binary forms, with or without 2448156Sjlemon * modification, are permitted provided that the following conditions 2548156Sjlemon * are met: 2648156Sjlemon * 1. Redistributions of source code must retain the copyright 2748156Sjlemon * notice, this list of conditions and the following disclaimer. 2848156Sjlemon * 2. Redistributions in binary form must reproduce the above copyright 2948156Sjlemon * notice, this list of conditions and the following disclaimer in the 3048156Sjlemon * documentation and/or other materials provided with the distribution. 31119418Sobrien * 3. All advertising materials mentioning features or use of this software 32119418Sobrien * must display the following acknowledgement: 33119418Sobrien * "This product includes cryptographic software written by 3448156Sjlemon * Eric Young (eay@cryptsoft.com)" 3548156Sjlemon * The word 'cryptographic' can be left out if the rouines from the library 3648156Sjlemon * being used are not cryptographic related :-). 3748156Sjlemon * 4. If you include any Windows specific code (or a derivative thereof) from 3848156Sjlemon * the apps directory (application code) you must include an acknowledgement: 3973113Sjlemon * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4048156Sjlemon * 41239740Sjhb * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4248156Sjlemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43239740Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44124540Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4548156Sjlemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4660041Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4748156Sjlemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48111337Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49124538Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5048156Sjlemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5148156Sjlemon * SUCH DAMAGE. 5248156Sjlemon * 5348156Sjlemon * The licence and distribution terms for any publically available version or 54112946Sphk * derivative of this code cannot be changed. i.e. this code cannot simply be 55112946Sphk * copied and put under another distribution licence 5648156Sjlemon * [including the GNU Public Licence.] 5748156Sjlemon */ 58124540Smdodd 5948156Sjlemon#include <stdio.h> 6048156Sjlemon#include <limits.h> 61239740Sjhb#include "cryptlib.h" 62239740Sjhb#include <openssl/asn1.h> 6348156Sjlemon#include <openssl/asn1_mac.h> 64239740Sjhb 65239740Sjhbstatic int asn1_get_length(unsigned char **pp,int *inf,long *rl,int max); 66239740Sjhbstatic void asn1_put_length(unsigned char **pp, int length); 6773113Sjlemonconst char *ASN1_version="ASN.1" OPENSSL_VERSION_PTEXT; 6848156Sjlemon 69124540Smdoddint ASN1_check_infinite_end(unsigned char **p, long len) 70124540Smdodd { 71126080Sphk /* If there is 0 or 1 byte left, the length check should pick 72124540Smdodd * things up */ 73124540Smdodd if (len <= 0) 74124540Smdodd return(1); 75124540Smdodd else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) 7648156Sjlemon { 7748156Sjlemon (*p)+=2; 7848156Sjlemon return(1); 7957828Sjlemon } 8048156Sjlemon return(0); 81239740Sjhb } 82239740Sjhb 83239740Sjhb 84239740Sjhbint ASN1_get_object(unsigned char **pp, long *plength, int *ptag, int *pclass, 85138853Smdodd long omax) 86239740Sjhb { 87239740Sjhb int i,ret; 88138853Smdodd long l; 89145024Smdodd unsigned char *p= *pp; 90239740Sjhb int tag,xclass,inf; 91145024Smdodd long max=omax; 9248156Sjlemon 93145024Smdodd if (!max) goto err; 9448156Sjlemon ret=(*p&V_ASN1_CONSTRUCTED); 95145024Smdodd xclass=(*p&V_ASN1_PRIVATE); 96145024Smdodd i= *p&V_ASN1_PRIMITIVE_TAG; 97145024Smdodd if (i == V_ASN1_PRIMITIVE_TAG) 98145024Smdodd { /* high-tag */ 99145024Smdodd p++; 100145024Smdodd if (--max == 0) goto err; 10148156Sjlemon l=0; 102145024Smdodd while (*p&0x80) 10348156Sjlemon { 10448156Sjlemon l<<=7L; 10548156Sjlemon l|= *(p++)&0x7f; 10648156Sjlemon if (--max == 0) goto err; 10748156Sjlemon } 10848156Sjlemon l<<=7L; 10948156Sjlemon l|= *(p++)&0x7f; 11048156Sjlemon tag=(int)l; 11148156Sjlemon } 11248156Sjlemon else 11348156Sjlemon { 11448156Sjlemon tag=i; 11548156Sjlemon p++; 11648156Sjlemon if (--max == 0) goto err; 117239740Sjhb } 118239740Sjhb *ptag=tag; 11948156Sjlemon *pclass=xclass; 12048156Sjlemon if (!asn1_get_length(&p,&inf,plength,(int)max)) goto err; 12148156Sjlemon 12248156Sjlemon#if 0 12348156Sjlemon fprintf(stderr,"p=%d + *plength=%ld > omax=%ld + *pp=%d (%d > %d)\n", 12448156Sjlemon (int)p,*plength,omax,(int)*pp,(int)(p+ *plength), 125144991Smdodd (int)(omax+ *pp)); 12648156Sjlemon 127144991Smdodd#endif 12848156Sjlemon if (*plength > (omax - (p - *pp))) 129144991Smdodd { 130144991Smdodd ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_TOO_LONG); 13148156Sjlemon /* Set this so that even if things are not long enough 13248156Sjlemon * the values are set correctly */ 13348156Sjlemon ret|=0x80; 13448156Sjlemon } 13548156Sjlemon *pp=p; 13648156Sjlemon return(ret|inf); 13748156Sjlemonerr: 13848156Sjlemon ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_HEADER_TOO_LONG); 13948156Sjlemon return(0x80); 140239740Sjhb } 14148156Sjlemon 14248156Sjlemonstatic int asn1_get_length(unsigned char **pp, int *inf, long *rl, int max) 14348156Sjlemon { 14448156Sjlemon unsigned char *p= *pp; 145239740Sjhb unsigned long ret=0; 146239740Sjhb int i; 147239740Sjhb 148239740Sjhb if (max-- < 1) return(0); 149239740Sjhb if (*p == 0x80) 150239740Sjhb { 151239740Sjhb *inf=1; 152239740Sjhb ret=0; 153239740Sjhb p++; 154239740Sjhb } 15557828Sjlemon else 15657828Sjlemon { 15757828Sjlemon *inf=0; 15857828Sjlemon i= *p&0x7f; 15957828Sjlemon if (*(p++) & 0x80) 16057828Sjlemon { 16157828Sjlemon if (i > sizeof(long)) 16257828Sjlemon return 0; 16357828Sjlemon if (max-- == 0) return(0); 16457828Sjlemon while (i-- > 0) 16557828Sjlemon { 16657828Sjlemon ret<<=8L; 16757828Sjlemon ret|= *(p++); 16857828Sjlemon if (max-- == 0) return(0); 16957828Sjlemon } 17057828Sjlemon } 17157828Sjlemon else 172239740Sjhb ret=i; 173239740Sjhb } 17448156Sjlemon if (ret > LONG_MAX) 17548156Sjlemon return 0; 176239740Sjhb *pp=p; 17748156Sjlemon *rl=(long)ret; 178239740Sjhb return(1); 179239740Sjhb } 18048156Sjlemon 181239740Sjhb/* class 0 is constructed 182239740Sjhb * constructed == 2 for indefinite length constructed */ 183239740Sjhbvoid ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, 18448156Sjlemon int xclass) 185239740Sjhb { 186239740Sjhb unsigned char *p= *pp; 187239740Sjhb int i, ttag; 188239740Sjhb 189239740Sjhb i=(constructed)?V_ASN1_CONSTRUCTED:0; 190239740Sjhb i|=(xclass&V_ASN1_PRIVATE); 191239740Sjhb if (tag < 31) 192239740Sjhb *(p++)=i|(tag&V_ASN1_PRIMITIVE_TAG); 19348156Sjlemon else 19448156Sjlemon { 19548156Sjlemon *(p++)=i|V_ASN1_PRIMITIVE_TAG; 19648156Sjlemon for(i = 0, ttag = tag; ttag > 0; i++) ttag >>=7; 19748156Sjlemon ttag = i; 198239740Sjhb while(i-- > 0) 199239740Sjhb { 200239740Sjhb p[i] = tag & 0x7f; 20148156Sjlemon if(i != (ttag - 1)) p[i] |= 0x80; 20248156Sjlemon tag >>= 7; 20348156Sjlemon } 204144991Smdodd p += ttag; 20548156Sjlemon } 20648156Sjlemon if ((constructed == 2) && (length == 0)) 20769781Sdwmalone *(p++)=0x80; /* der_put_length would output 0 instead */ 20869781Sdwmalone else 20948156Sjlemon asn1_put_length(&p,length); 21048156Sjlemon *pp=p; 21148156Sjlemon } 21248156Sjlemon 21348156Sjlemonstatic void asn1_put_length(unsigned char **pp, int length) 21448156Sjlemon { 21548156Sjlemon unsigned char *p= *pp; 21648156Sjlemon int i,l; 217138851Smdodd if (length <= 127) 218138851Smdodd *(p++)=(unsigned char)length; 219138851Smdodd else 220138851Smdodd { 221138851Smdodd l=length; 222138851Smdodd for (i=0; l > 0; i++) 223138851Smdodd l>>=8; 224138851Smdodd *(p++)=i|0x80; 225138851Smdodd l=i; 226138851Smdodd while (i-- > 0) 227138851Smdodd { 228138851Smdodd p[i]=length&0xff; 229239740Sjhb length>>=8; 230239740Sjhb } 231138851Smdodd p+=l; 23248156Sjlemon } 233144991Smdodd *pp=p; 23448156Sjlemon } 23548156Sjlemon 236138851Smdoddint ASN1_object_size(int constructed, int length, int tag) 237138851Smdodd { 238138851Smdodd int ret; 239138851Smdodd 240138851Smdodd ret=length; 241138851Smdodd ret++; 242138851Smdodd if (tag >= 31) 243138851Smdodd { 244281826Smav while (tag > 0) 245138851Smdodd { 246138851Smdodd tag>>=7; 247138851Smdodd ret++; 248138851Smdodd } 249138851Smdodd } 250138851Smdodd if ((length == 0) && (constructed == 2)) 25148156Sjlemon ret+=2; 252144991Smdodd ret++; 25348156Sjlemon if (length > 127) 254144991Smdodd { 25548156Sjlemon while (length > 0) 25648156Sjlemon { 25748156Sjlemon length>>=8; 25848156Sjlemon ret++; 259144991Smdodd } 26048156Sjlemon } 261144991Smdodd return(ret); 262144991Smdodd } 26348156Sjlemon 26448156Sjlemonint asn1_Finish(ASN1_CTX *c) 26548156Sjlemon { 26648156Sjlemon if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos)) 26748156Sjlemon { 268239740Sjhb if (!ASN1_check_infinite_end(&c->p,c->slen)) 269239740Sjhb { 270239740Sjhb c->error=ERR_R_MISSING_ASN1_EOS; 27148156Sjlemon return(0); 272239740Sjhb } 27357828Sjlemon } 27448156Sjlemon if ( ((c->slen != 0) && !(c->inf & 1)) || 27548156Sjlemon ((c->slen < 0) && (c->inf & 1))) 27673113Sjlemon { 27748156Sjlemon c->error=ERR_R_ASN1_LENGTH_MISMATCH; 278239740Sjhb return(0); 27948156Sjlemon } 280239740Sjhb return(1); 28148156Sjlemon } 28248156Sjlemon 28348156Sjlemonint asn1_GetSequence(ASN1_CTX *c, long *length) 28448156Sjlemon { 28548156Sjlemon unsigned char *q; 28648156Sjlemon 28763934Sjlemon q=c->p; 28863934Sjlemon c->inf=ASN1_get_object(&(c->p),&(c->slen),&(c->tag),&(c->xclass), 28948156Sjlemon *length); 29063934Sjlemon if (c->inf & 0x80) 29173113Sjlemon { 29263934Sjlemon c->error=ERR_R_BAD_GET_ASN1_OBJECT_CALL; 293239740Sjhb return(0); 29463934Sjlemon } 295239740Sjhb if (c->tag != V_ASN1_SEQUENCE) 29663934Sjlemon { 29763934Sjlemon c->error=ERR_R_EXPECTING_AN_ASN1_SEQUENCE; 298239740Sjhb return(0); 299239740Sjhb } 300239740Sjhb (*length)-=(c->p-q); 301239740Sjhb if (c->max && (*length < 0)) 30263934Sjlemon { 303239740Sjhb c->error=ERR_R_ASN1_LENGTH_MISMATCH; 304239740Sjhb return(0); 305239740Sjhb } 306239740Sjhb if (c->inf == (1|V_ASN1_CONSTRUCTED)) 307239740Sjhb c->slen= *length+ *(c->pp)-c->p; 308239740Sjhb c->eos=0; 309239740Sjhb return(1); 310239740Sjhb } 311239740Sjhb 312239740SjhbASN1_STRING *ASN1_STRING_dup(ASN1_STRING *str) 313239740Sjhb { 314239740Sjhb ASN1_STRING *ret; 315239740Sjhb 316239740Sjhb if (str == NULL) return(NULL); 317239740Sjhb if ((ret=ASN1_STRING_type_new(str->type)) == NULL) 318239740Sjhb return(NULL); 319124540Smdodd if (!ASN1_STRING_set(ret,str->data,str->length)) 320239740Sjhb { 321124540Smdodd ASN1_STRING_free(ret); 322124540Smdodd return(NULL); 323239740Sjhb } 324239740Sjhb ret->flags = str->flags; 32548156Sjlemon return(ret); 326239740Sjhb } 327239740Sjhb 328239740Sjhbint ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) 329239740Sjhb { 330239740Sjhb unsigned char *c; 331239740Sjhb const char *data=_data; 332239740Sjhb 333239740Sjhb if (len < 0) 334239740Sjhb { 335239740Sjhb if (data == NULL) 33648156Sjlemon return(0); 337239740Sjhb else 33848156Sjlemon len=strlen(data); 33948156Sjlemon } 34057828Sjlemon if ((str->length < len) || (str->data == NULL)) 34157828Sjlemon { 34257828Sjlemon c=str->data; 34357828Sjlemon if (c == NULL) 344239740Sjhb str->data=OPENSSL_malloc(len+1); 34557828Sjlemon else 346144991Smdodd str->data=OPENSSL_realloc(c,len+1); 34757828Sjlemon 348239740Sjhb if (str->data == NULL) 349239740Sjhb { 350239740Sjhb str->data=c; 351239740Sjhb return(0); 352239740Sjhb } 353239740Sjhb } 354239740Sjhb str->length=len; 35557828Sjlemon if (data != NULL) 35657828Sjlemon { 357144991Smdodd memcpy(str->data,data,len); 35857828Sjlemon /* an allowance for strings :-) */ 35957828Sjlemon str->data[len]='\0'; 36057828Sjlemon } 36157828Sjlemon return(1); 36257828Sjlemon } 36357828Sjlemon 36457828SjlemonASN1_STRING *ASN1_STRING_new(void) 36557828Sjlemon { 36657828Sjlemon return(ASN1_STRING_type_new(V_ASN1_OCTET_STRING)); 367124540Smdodd } 36857828Sjlemon 36957828Sjlemon 37057828SjlemonASN1_STRING *ASN1_STRING_type_new(int type) 37157828Sjlemon { 37248156Sjlemon ASN1_STRING *ret; 373239740Sjhb 37448156Sjlemon ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING)); 375239740Sjhb if (ret == NULL) 376239740Sjhb { 377239740Sjhb ASN1err(ASN1_F_ASN1_STRING_TYPE_NEW,ERR_R_MALLOC_FAILURE); 378239740Sjhb return(NULL); 37948156Sjlemon } 38048156Sjlemon ret->length=0; 381239740Sjhb ret->type=type; 382239740Sjhb ret->data=NULL; 383239740Sjhb ret->flags=0; 384239740Sjhb return(ret); 385239740Sjhb } 386239740Sjhb 387239740Sjhbvoid ASN1_STRING_free(ASN1_STRING *a) 388239740Sjhb { 389239740Sjhb if (a == NULL) return; 390239740Sjhb if (a->data != NULL) OPENSSL_free(a->data); 391239740Sjhb OPENSSL_free(a); 392144991Smdodd } 393124538Smdodd 39448156Sjlemonint ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b) 39548156Sjlemon { 396124538Smdodd int i; 397124538Smdodd 39848156Sjlemon i=(a->length-b->length); 39948156Sjlemon if (i == 0) 400239740Sjhb { 401239740Sjhb i=memcmp(a->data,b->data,a->length); 402239740Sjhb if (i == 0) 403239740Sjhb return(a->type-b->type); 404239740Sjhb else 405239740Sjhb return(i); 406239740Sjhb } 407239740Sjhb else 408239740Sjhb return(i); 409239740Sjhb } 410239740Sjhb 411239740Sjhbvoid asn1_add_error(unsigned char *address, int offset) 412239740Sjhb { 413239740Sjhb char buf1[DECIMAL_SIZE(address)+1],buf2[DECIMAL_SIZE(offset)+1]; 414239740Sjhb 415239740Sjhb sprintf(buf1,"%lu",(unsigned long)address); 416239740Sjhb sprintf(buf2,"%d",offset); 417239740Sjhb ERR_add_error_data(4,"address=",buf1," offset=",buf2); 418239740Sjhb } 419239740Sjhb 420239740Sjhbint ASN1_STRING_length(ASN1_STRING *x) 421239740Sjhb{ return M_ASN1_STRING_length(x); } 42248156Sjlemon 42348156Sjlemonvoid ASN1_STRING_length_set(ASN1_STRING *x, int len) 424239740Sjhb{ M_ASN1_STRING_length_set(x, len); return; } 425239740Sjhb 426239740Sjhbint ASN1_STRING_type(ASN1_STRING *x) 427239740Sjhb{ return M_ASN1_STRING_type(x); } 428239740Sjhb 429239740Sjhbunsigned char * ASN1_STRING_data(ASN1_STRING *x) 430239740Sjhb{ return M_ASN1_STRING_data(x); } 431239740Sjhb