summaryrefslogtreecommitdiff
path: root/crypto/asn1/a_object.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/asn1/a_object.c')
-rw-r--r--crypto/asn1/a_object.c127
1 files changed, 105 insertions, 22 deletions
diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c
index 715042e6eb..bd2d5a2d82 100644
--- a/crypto/asn1/a_object.c
+++ b/crypto/asn1/a_object.c
@@ -57,10 +57,12 @@
*/
#include <stdio.h>
+#include <limits.h>
#include "cryptlib.h"
#include <openssl/buffer.h>
#include <openssl/asn1.h>
#include <openssl/objects.h>
+#include <openssl/bn.h>
int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
{
@@ -83,10 +85,12 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
{
- int i,first,len=0,c;
- char tmp[24];
+ int i,first,len=0,c, use_bn;
+ char ftmp[24], *tmp = ftmp;
+ int tmpsize = sizeof ftmp;
const char *p;
unsigned long l;
+ BIGNUM *bl = NULL;
if (num == 0)
return(0);
@@ -98,7 +102,7 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
num--;
if ((c >= '0') && (c <= '2'))
{
- first=(c-'0')*40;
+ first= c-'0';
}
else
{
@@ -122,6 +126,7 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
goto err;
}
l=0;
+ use_bn = 0;
for (;;)
{
if (num <= 0) break;
@@ -134,7 +139,22 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
ASN1err(ASN1_F_A2D_ASN1_OBJECT,ASN1_R_INVALID_DIGIT);
goto err;
}
- l=l*10L+(long)(c-'0');
+ if (!use_bn && l > (ULONG_MAX / 10L))
+ {
+ use_bn = 1;
+ if (!bl)
+ bl = BN_new();
+ if (!bl || !BN_set_word(bl, l))
+ goto err;
+ }
+ if (use_bn)
+ {
+ if (!BN_mul_word(bl, 10L)
+ || !BN_add_word(bl, c-'0'))
+ goto err;
+ }
+ else
+ l=l*10L+(long)(c-'0');
}
if (len == 0)
{
@@ -143,14 +163,42 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
ASN1err(ASN1_F_A2D_ASN1_OBJECT,ASN1_R_SECOND_NUMBER_TOO_LARGE);
goto err;
}
- l+=(long)first;
+ if (use_bn)
+ {
+ if (!BN_add_word(bl, first * 40))
+ goto err;
+ }
+ else
+ l+=(long)first*40;
}
i=0;
- for (;;)
+ if (use_bn)
{
- tmp[i++]=(unsigned char)l&0x7f;
- l>>=7L;
- if (l == 0L) break;
+ int blsize;
+ blsize = BN_num_bits(bl);
+ blsize = (blsize + 6)/7;
+ if (blsize > tmpsize)
+ {
+ if (tmp != ftmp)
+ OPENSSL_free(tmp);
+ tmpsize = blsize + 32;
+ tmp = OPENSSL_malloc(tmpsize);
+ if (!tmp)
+ goto err;
+ }
+ while(blsize--)
+ tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L);
+ }
+ else
+ {
+
+ for (;;)
+ {
+ tmp[i++]=(unsigned char)l&0x7f;
+ l>>=7L;
+ if (l == 0L) break;
+ }
+
}
if (out != NULL)
{
@@ -166,8 +214,16 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
else
len+=i;
}
+ if (tmp != ftmp)
+ OPENSSL_free(tmp);
+ if (bl)
+ BN_free(bl);
return(len);
err:
+ if (tmp != ftmp)
+ OPENSSL_free(tmp);
+ if (bl)
+ BN_free(bl);
return(0);
}
@@ -178,14 +234,24 @@ int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a)
int i2a_ASN1_OBJECT(BIO *bp, ASN1_OBJECT *a)
{
- char buf[80];
+ char buf[80], *p = buf;
int i;
if ((a == NULL) || (a->data == NULL))
return(BIO_write(bp,"NULL",4));
i=i2t_ASN1_OBJECT(buf,sizeof buf,a);
- if (i > (int)sizeof(buf)) i=sizeof buf;
- BIO_write(bp,buf,i);
+ if (i > (int)(sizeof(buf) - 1))
+ {
+ p = OPENSSL_malloc(i + 1);
+ if (!p)
+ return -1;
+ i2t_ASN1_OBJECT(p,i + 1,a);
+ }
+ if (i <= 0)
+ return BIO_write(bp, "<INVALID>", 9);
+ BIO_write(bp,p,i);
+ if (p != buf)
+ OPENSSL_free(p);
return(i);
}
@@ -215,8 +281,6 @@ ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
return ret;
err:
ASN1err(ASN1_F_D2I_ASN1_OBJECT,i);
- if ((ret != NULL) && ((a == NULL) || (*a != ret)))
- ASN1_OBJECT_free(ret);
return(NULL);
}
ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
@@ -224,7 +288,19 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
{
ASN1_OBJECT *ret=NULL;
const unsigned char *p;
+ unsigned char *data;
int i;
+ /* Sanity check OID encoding: can't have 0x80 in subidentifiers, see:
+ * X.690 8.19.2
+ */
+ for (i = 0, p = *pp + 1; i < len - 1; i++, p++)
+ {
+ if (*p == 0x80)
+ {
+ ASN1err(ASN1_F_C2I_ASN1_OBJECT,ASN1_R_INVALID_OBJECT_ENCODING);
+ return NULL;
+ }
+ }
/* only the ASN1_OBJECTs from the 'table' will have values
* for ->sn or ->ln */
@@ -236,15 +312,22 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
else ret=(*a);
p= *pp;
- if ((ret->data == NULL) || (ret->length < len))
+ /* detach data from object */
+ data = (unsigned char *)ret->data;
+ ret->data = NULL;
+ /* once detached we can change it */
+ if ((data == NULL) || (ret->length < len))
{
- if (ret->data != NULL) OPENSSL_free(ret->data);
- ret->data=(unsigned char *)OPENSSL_malloc(len ? (int)len : 1);
- ret->flags|=ASN1_OBJECT_FLAG_DYNAMIC_DATA;
- if (ret->data == NULL)
+ ret->length=0;
+ if (data != NULL) OPENSSL_free(data);
+ data=(unsigned char *)OPENSSL_malloc(len ? (int)len : 1);
+ if (data == NULL)
{ i=ERR_R_MALLOC_FAILURE; goto err; }
+ ret->flags|=ASN1_OBJECT_FLAG_DYNAMIC_DATA;
}
- memcpy(ret->data,p,(int)len);
+ memcpy(data,p,(int)len);
+ /* reattach data to object, after which it remains const */
+ ret->data =data;
ret->length=(int)len;
ret->sn=NULL;
ret->ln=NULL;
@@ -255,7 +338,7 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
*pp=p;
return(ret);
err:
- ASN1err(ASN1_F_D2I_ASN1_OBJECT,i);
+ ASN1err(ASN1_F_C2I_ASN1_OBJECT,i);
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
ASN1_OBJECT_free(ret);
return(NULL);
@@ -293,7 +376,7 @@ void ASN1_OBJECT_free(ASN1_OBJECT *a)
}
if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA)
{
- if (a->data != NULL) OPENSSL_free(a->data);
+ if (a->data != NULL) OPENSSL_free((void *)a->data);
a->data=NULL;
a->length=0;
}