IPv6 display and input support for extensions usingh GeneralName.
This commit is contained in:
parent
379e568950
commit
4e5d3a7f98
6
CHANGES
6
CHANGES
@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
Changes between 0.9.7 and 0.9.8 [xx XXX xxxx]
|
Changes between 0.9.7 and 0.9.8 [xx XXX xxxx]
|
||||||
|
|
||||||
|
*) IPv6 support for certificate extensions. The various extensions
|
||||||
|
which use the IP:a.b.c.d can now take IPv6 addresses using the
|
||||||
|
formats of RFC1884 2.2 . IPv6 addresses are now also displayed
|
||||||
|
correctly.
|
||||||
|
[Steve Henson]
|
||||||
|
|
||||||
*) Added an ENGINE that implements RSA by performing private key
|
*) Added an ENGINE that implements RSA by performing private key
|
||||||
exponentiations with the GMP library. The conversions to and from
|
exponentiations with the GMP library. The conversions to and from
|
||||||
GMP's mpz_t format aren't optimised nor are any montgomery forms
|
GMP's mpz_t format aren't optimised nor are any montgomery forms
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/* v3_alt.c */
|
/* v3_alt.c */
|
||||||
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
||||||
* project 1999.
|
* project.
|
||||||
*/
|
*/
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
* Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved.
|
* Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -100,7 +100,8 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
|
|||||||
GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret)
|
GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
char oline[256];
|
char oline[256], htmp[5];
|
||||||
|
int i;
|
||||||
switch (gen->type)
|
switch (gen->type)
|
||||||
{
|
{
|
||||||
case GEN_OTHERNAME:
|
case GEN_OTHERNAME:
|
||||||
@ -134,12 +135,25 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
|
|||||||
|
|
||||||
case GEN_IPADD:
|
case GEN_IPADD:
|
||||||
p = gen->d.ip->data;
|
p = gen->d.ip->data;
|
||||||
/* BUG: doesn't support IPV6 */
|
if(gen->d.ip->length == 4)
|
||||||
if(gen->d.ip->length != 4) {
|
sprintf(oline, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
||||||
|
else if(gen->d.ip->length == 16)
|
||||||
|
{
|
||||||
|
oline[0] = 0;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
sprintf(htmp, "%X", p[0] << 8 | p[1]);
|
||||||
|
p += 2;
|
||||||
|
strcat(oline, htmp);
|
||||||
|
if (i != 7)
|
||||||
|
strcat(oline, ":");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
X509V3_add_value("IP Address","<invalid>", &ret);
|
X509V3_add_value("IP Address","<invalid>", &ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sprintf(oline, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
|
||||||
X509V3_add_value("IP Address",oline, &ret);
|
X509V3_add_value("IP Address",oline, &ret);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -154,6 +168,7 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
|
|||||||
int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
|
int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
int i;
|
||||||
switch (gen->type)
|
switch (gen->type)
|
||||||
{
|
{
|
||||||
case GEN_OTHERNAME:
|
case GEN_OTHERNAME:
|
||||||
@ -188,12 +203,24 @@ int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
|
|||||||
|
|
||||||
case GEN_IPADD:
|
case GEN_IPADD:
|
||||||
p = gen->d.ip->data;
|
p = gen->d.ip->data;
|
||||||
/* BUG: doesn't support IPV6 */
|
if(gen->d.ip->length == 4)
|
||||||
if(gen->d.ip->length != 4) {
|
BIO_printf(out, "IP Address:%d.%d.%d.%d",
|
||||||
|
p[0], p[1], p[2], p[3]);
|
||||||
|
else if(gen->d.ip->length == 16)
|
||||||
|
{
|
||||||
|
BIO_printf(out, "IP Address");
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
BIO_printf(out, ":%X", p[0] << 8 | p[1]);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
BIO_puts(out, "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
BIO_printf(out,"IP Address:<invalid>");
|
BIO_printf(out,"IP Address:<invalid>");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_RID:
|
case GEN_RID:
|
||||||
@ -418,21 +445,12 @@ if(!name_cmp(name, "email")) {
|
|||||||
gen->d.rid = obj;
|
gen->d.rid = obj;
|
||||||
type = GEN_RID;
|
type = GEN_RID;
|
||||||
} else if(!name_cmp(name, "IP")) {
|
} else if(!name_cmp(name, "IP")) {
|
||||||
int i1,i2,i3,i4;
|
if(!(gen->d.ip = a2i_IPADDRESS(value)))
|
||||||
unsigned char ip[4];
|
{
|
||||||
if((sscanf(value, "%d.%d.%d.%d",&i1,&i2,&i3,&i4) != 4) ||
|
|
||||||
(i1 < 0) || (i1 > 255) || (i2 < 0) || (i2 > 255) ||
|
|
||||||
(i3 < 0) || (i3 > 255) || (i4 < 0) || (i4 > 255) ) {
|
|
||||||
X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_BAD_IP_ADDRESS);
|
X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_BAD_IP_ADDRESS);
|
||||||
ERR_add_error_data(2, "value=", value);
|
ERR_add_error_data(2, "value=", value);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
ip[0] = i1; ip[1] = i2 ; ip[2] = i3 ; ip[3] = i4;
|
|
||||||
if(!(gen->d.ip = M_ASN1_OCTET_STRING_new()) ||
|
|
||||||
!ASN1_STRING_set(gen->d.ip, ip, 4)) {
|
|
||||||
X509V3err(X509V3_F_V2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
type = GEN_IPADD;
|
type = GEN_IPADD;
|
||||||
} else if(!name_cmp(name, "otherName")) {
|
} else if(!name_cmp(name, "otherName")) {
|
||||||
if (!do_othername(gen, value, ctx))
|
if (!do_othername(gen, value, ctx))
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/* v3_utl.c */
|
/* v3_utl.c */
|
||||||
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
||||||
* project 1999.
|
* project.
|
||||||
*/
|
*/
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
|
* Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -70,6 +70,11 @@ static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens);
|
|||||||
static void str_free(void *str);
|
static void str_free(void *str);
|
||||||
static int append_ia5(STACK **sk, ASN1_IA5STRING *email);
|
static int append_ia5(STACK **sk, ASN1_IA5STRING *email);
|
||||||
|
|
||||||
|
static int ipv4_from_asc(unsigned char *v4, const char *in);
|
||||||
|
static int ipv6_from_asc(unsigned char *v6, const char *in);
|
||||||
|
static int ipv6_cb(const char *elem, int len, void *usr);
|
||||||
|
static int ipv6_hex(unsigned char *out, const char *in, int inlen);
|
||||||
|
|
||||||
/* Add a CONF_VALUE name value pair to stack */
|
/* Add a CONF_VALUE name value pair to stack */
|
||||||
|
|
||||||
int X509V3_add_value(const char *name, const char *value,
|
int X509V3_add_value(const char *name, const char *value,
|
||||||
@ -534,3 +539,204 @@ void X509_email_free(STACK *sk)
|
|||||||
{
|
{
|
||||||
sk_pop_free(sk, str_free);
|
sk_pop_free(sk, str_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert IP addresses both IPv4 and IPv6 into an
|
||||||
|
* OCTET STRING compatible with RFC3280.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
|
||||||
|
{
|
||||||
|
unsigned char ipout[16];
|
||||||
|
ASN1_OCTET_STRING *ret;
|
||||||
|
int iplen;
|
||||||
|
|
||||||
|
/* If string contains a ':' assume IPv6 */
|
||||||
|
|
||||||
|
if (strchr(ipasc, ':'))
|
||||||
|
{
|
||||||
|
if (!ipv6_from_asc(ipout, ipasc))
|
||||||
|
return NULL;
|
||||||
|
iplen = 16;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!ipv4_from_asc(ipout, ipasc))
|
||||||
|
return NULL;
|
||||||
|
iplen = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ASN1_OCTET_STRING_new();
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
if (!ASN1_OCTET_STRING_set(ret, ipout, iplen))
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING_free(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipv4_from_asc(unsigned char *v4, const char *in)
|
||||||
|
{
|
||||||
|
int a0, a1, a2, a3;
|
||||||
|
if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4)
|
||||||
|
return 0;
|
||||||
|
if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
|
||||||
|
|| (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255))
|
||||||
|
return 0;
|
||||||
|
v4[0] = a0;
|
||||||
|
v4[1] = a1;
|
||||||
|
v4[2] = a2;
|
||||||
|
v4[3] = a3;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* Temporary store for IPV6 output */
|
||||||
|
unsigned char tmp[16];
|
||||||
|
/* Total number of bytes in tmp */
|
||||||
|
int total;
|
||||||
|
/* The position of a zero (corresponding to '::') */
|
||||||
|
int zero_pos;
|
||||||
|
/* Number of zeroes */
|
||||||
|
int zero_cnt;
|
||||||
|
} IPV6_STAT;
|
||||||
|
|
||||||
|
|
||||||
|
static int ipv6_from_asc(unsigned char *v6, const char *in)
|
||||||
|
{
|
||||||
|
IPV6_STAT v6stat;
|
||||||
|
v6stat.total = 0;
|
||||||
|
v6stat.zero_pos = -1;
|
||||||
|
v6stat.zero_cnt = 0;
|
||||||
|
/* Treat the IPv6 representation as a list of values
|
||||||
|
* separated by ':'. The presence of a '::' will parse
|
||||||
|
* as one, two or three zero length elements.
|
||||||
|
*/
|
||||||
|
if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Now for some sanity checks */
|
||||||
|
|
||||||
|
if (v6stat.zero_pos == -1)
|
||||||
|
{
|
||||||
|
/* If no '::' must have exactly 16 bytes */
|
||||||
|
if (v6stat.total != 16)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If '::' must have less than 16 bytes */
|
||||||
|
if (v6stat.total == 16)
|
||||||
|
return 0;
|
||||||
|
/* More than three zeroes is an error */
|
||||||
|
if (v6stat.zero_cnt > 3)
|
||||||
|
return 0;
|
||||||
|
/* Can only have three zeroes if nothing else present */
|
||||||
|
else if (v6stat.zero_cnt == 3)
|
||||||
|
{
|
||||||
|
if (v6stat.total > 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Can only have two zeroes if at start or end */
|
||||||
|
else if (v6stat.zero_cnt == 2)
|
||||||
|
{
|
||||||
|
if ((v6stat.zero_pos != 0)
|
||||||
|
&& (v6stat.zero_pos != v6stat.total))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Can only have one zero if *not* start or end */
|
||||||
|
{
|
||||||
|
if ((v6stat.zero_pos == 0)
|
||||||
|
|| (v6stat.zero_pos == v6stat.total))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format result */
|
||||||
|
|
||||||
|
/* Copy initial part */
|
||||||
|
if (v6stat.zero_pos > 0)
|
||||||
|
memcpy(v6, v6stat.tmp, v6stat.zero_pos);
|
||||||
|
/* Zero middle */
|
||||||
|
if (v6stat.total != 16)
|
||||||
|
memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total);
|
||||||
|
/* Copy final part */
|
||||||
|
if (v6stat.total != v6stat.zero_pos)
|
||||||
|
memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
|
||||||
|
v6stat.tmp + v6stat.zero_pos,
|
||||||
|
v6stat.total - v6stat.zero_pos);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipv6_cb(const char *elem, int len, void *usr)
|
||||||
|
{
|
||||||
|
IPV6_STAT *s = usr;
|
||||||
|
/* Error if 16 bytes written */
|
||||||
|
if (s->total == 16)
|
||||||
|
return 0;
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
/* Zero length element, corresponds to '::' */
|
||||||
|
if (s->zero_pos == -1)
|
||||||
|
s->zero_pos = s->total;
|
||||||
|
/* If we've already got a :: its an error */
|
||||||
|
else if (s->zero_pos != s->total)
|
||||||
|
return 0;
|
||||||
|
s->zero_cnt++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If more than 4 characters could be final a.b.c.d form */
|
||||||
|
if (len > 4)
|
||||||
|
{
|
||||||
|
/* Need at least 4 bytes left */
|
||||||
|
if (s->total > 12)
|
||||||
|
return 0;
|
||||||
|
/* Must be end of string */
|
||||||
|
if (elem[len])
|
||||||
|
return 0;
|
||||||
|
if (!ipv4_from_asc(s->tmp + s->total, elem))
|
||||||
|
return 0;
|
||||||
|
s->total += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!ipv6_hex(s->tmp + s->total, elem, len))
|
||||||
|
return 0;
|
||||||
|
s->total += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a string of up to 4 hex digits into the corresponding
|
||||||
|
* IPv6 form.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int ipv6_hex(unsigned char *out, const char *in, int inlen)
|
||||||
|
{
|
||||||
|
unsigned char c;
|
||||||
|
unsigned int num = 0;
|
||||||
|
if (inlen > 4)
|
||||||
|
return 0;
|
||||||
|
while(inlen--)
|
||||||
|
{
|
||||||
|
c = *in++;
|
||||||
|
num <<= 4;
|
||||||
|
if ((c >= '0') && (c <= '9'))
|
||||||
|
num |= c - '0';
|
||||||
|
else if ((c >= 'A') && (c <= 'F'))
|
||||||
|
num |= c - 'A' + 10;
|
||||||
|
else if ((c >= 'a') && (c <= 'f'))
|
||||||
|
num |= c - 'a' + 10;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out[0] = num >> 8;
|
||||||
|
out[1] = num & 0xff;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -547,6 +547,7 @@ STACK *X509_get1_email(X509 *x);
|
|||||||
STACK *X509_REQ_get1_email(X509_REQ *x);
|
STACK *X509_REQ_get1_email(X509_REQ *x);
|
||||||
void X509_email_free(STACK *sk);
|
void X509_email_free(STACK *sk);
|
||||||
|
|
||||||
|
ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
|
||||||
|
|
||||||
/* BEGIN ERROR CODES */
|
/* BEGIN ERROR CODES */
|
||||||
/* The following lines are auto generated by the script mkerr.pl. Any changes
|
/* The following lines are auto generated by the script mkerr.pl. Any changes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user