Fix get_email: 0 is a valid return value
[openssl.git] / crypto / x509v3 / v3_utl.c
index 6234694f16b6d8f1cac22c4d3efaf4f6ac8ffeb6..a11243db8f663f4cbe3a892992f82a52cdf63f3b 100644 (file)
 #include <stdio.h>
 #include <ctype.h>
 #include "cryptlib.h"
-#include "conf.h"
-#include "x509v3.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
 
 static char *strip_spaces(char *name);
+static int sk_strcmp(const char * const *a, const char * const *b);
+static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens);
+static void str_free(void *str);
+static int append_ia5(STACK **sk, ASN1_IA5STRING *email);
 
 /* Add a CONF_VALUE name value pair to stack */
 
-int X509V3_add_value(const char *name, const char *value, STACK **extlist)
+int X509V3_add_value(const char *name, const char *value,
+                                               STACK_OF(CONF_VALUE) **extlist)
 {
        CONF_VALUE *vtmp = NULL;
        char *tname = NULL, *tvalue = NULL;
        if(name && !(tname = BUF_strdup(name))) goto err;
        if(value && !(tvalue = BUF_strdup(value))) goto err;;
-       if(!(vtmp = (CONF_VALUE *)Malloc(sizeof(CONF_VALUE)))) goto err;
-       if(!*extlist && !(*extlist = sk_new(NULL))) goto err;
+       if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err;
+       if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err;
        vtmp->section = NULL;
        vtmp->name = tname;
        vtmp->value = tvalue;
-       if(!sk_push(*extlist, (char *)vtmp)) goto err;
+       if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err;
        return 1;
        err:
        X509V3err(X509V3_F_X509V3_ADD_VALUE,ERR_R_MALLOC_FAILURE);
-       if(vtmp) Free(vtmp);
-       if(tname) Free(tname);
-       if(tvalue) Free(tvalue);
+       if(vtmp) OPENSSL_free(vtmp);
+       if(tname) OPENSSL_free(tname);
+       if(tvalue) OPENSSL_free(tvalue);
        return 0;
 }
 
 int X509V3_add_value_uchar(const char *name, const unsigned char *value,
-                          STACK **extlist)
+                          STACK_OF(CONF_VALUE) **extlist)
     {
     return X509V3_add_value(name,(const char *)value,extlist);
     }
 
-/* Free function for STACK of CONF_VALUE */
+/* Free function for STACK_OF(CONF_VALUE) */
 
 void X509V3_conf_free(CONF_VALUE *conf)
 {
        if(!conf) return;
-       if(conf->name) Free(conf->name);
-       if(conf->value) Free(conf->value);
-       if(conf->section) Free(conf->section);
-       Free((char *)conf);
+       if(conf->name) OPENSSL_free(conf->name);
+       if(conf->value) OPENSSL_free(conf->value);
+       if(conf->section) OPENSSL_free(conf->section);
+       OPENSSL_free(conf);
 }
 
-int X509V3_add_value_bool(const char *name, int asn1_bool, STACK **extlist)
+int X509V3_add_value_bool(const char *name, int asn1_bool,
+                                               STACK_OF(CONF_VALUE) **extlist)
 {
        if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist);
        return X509V3_add_value(name, "FALSE", extlist);
 }
 
-int X509V3_add_value_bool_nf(char *name, int asn1_bool, STACK **extlist)
+int X509V3_add_value_bool_nf(char *name, int asn1_bool,
+                                               STACK_OF(CONF_VALUE) **extlist)
 {
        if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist);
        return 1;
@@ -147,33 +154,53 @@ ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value)
 {
        BIGNUM *bn = NULL;
        ASN1_INTEGER *aint;
-       bn = BN_new();
-       if(!value) {
+       int isneg, ishex;
+       int ret;
+       if (!value) {
                X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_INVALID_NULL_VALUE);
                return 0;
        }
-       if(!BN_dec2bn(&bn, value)) {
+       bn = BN_new();
+       if (value[0] == '-') {
+               value++;
+               isneg = 1;
+       } else isneg = 0;
+
+       if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) {
+               value += 2;
+               ishex = 1;
+       } else ishex = 0;
+
+       if (ishex) ret = BN_hex2bn(&bn, value);
+       else ret = BN_dec2bn(&bn, value);
+
+       if (!ret || value[ret]) {
+               BN_free(bn);
                X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_DEC2BN_ERROR);
                return 0;
        }
 
-       if(!(aint = BN_to_ASN1_INTEGER(bn, NULL))) {
+       if (isneg && BN_is_zero(bn)) isneg = 0;
+
+       aint = BN_to_ASN1_INTEGER(bn, NULL);
+       BN_free(bn);
+       if (!aint) {
                X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
                return 0;
        }
-       BN_free(bn);
+       if (isneg) aint->type |= V_ASN1_NEG;
        return aint;
 }
 
 int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
-            STACK **extlist)
+            STACK_OF(CONF_VALUE) **extlist)
 {
        char *strtmp;
        int ret;
        if(!aint) return 1;
        if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0;
        ret = X509V3_add_value(name, strtmp, extlist);
-       Free(strtmp);
+       OPENSSL_free(strtmp);
        return ret;
 }
 
@@ -214,11 +241,11 @@ int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint)
 
 /*#define DEBUG*/
 
-STACK *X509V3_parse_list(char *line)
+STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line)
 {
        char *p, *q, c;
        char *ntmp, *vtmp;
-       STACK *values = NULL;
+       STACK_OF(CONF_VALUE) *values = NULL;
        char *linebuf;
        int state;
        /* We are going to modify the line so copy it first */
@@ -243,7 +270,7 @@ STACK *X509V3_parse_list(char *line)
                                *p = 0;
                                ntmp = strip_spaces(q);
                                q = p + 1;
-#ifdef DEBUG
+#if 0
                                printf("%s\n", ntmp);
 #endif
                                if(!ntmp) {
@@ -259,7 +286,7 @@ STACK *X509V3_parse_list(char *line)
                                state = HDR_NAME;
                                *p = 0;
                                vtmp = strip_spaces(q);
-#ifdef DEBUG
+#if 0
                                printf("%s\n", ntmp);
 #endif
                                if(!vtmp) {
@@ -276,7 +303,7 @@ STACK *X509V3_parse_list(char *line)
 
        if(state == HDR_VALUE) {
                vtmp = strip_spaces(q);
-#ifdef DEBUG
+#if 0
                printf("%s=%s\n", ntmp, vtmp);
 #endif
                if(!vtmp) {
@@ -286,7 +313,7 @@ STACK *X509V3_parse_list(char *line)
                X509V3_add_value(ntmp, vtmp, &values);
        } else {
                ntmp = strip_spaces(q);
-#ifdef DEBUG
+#if 0
                printf("%s\n", ntmp);
 #endif
                if(!ntmp) {
@@ -295,12 +322,12 @@ STACK *X509V3_parse_list(char *line)
                }
                X509V3_add_value(ntmp, NULL, &values);
        }
-Free(linebuf);
+OPENSSL_free(linebuf);
 return values;
 
 err:
-Free(linebuf);
-sk_pop_free(values, X509V3_conf_free);
+OPENSSL_free(linebuf);
+sk_CONF_VALUE_pop_free(values, X509V3_conf_free);
 return NULL;
 
 }
@@ -311,10 +338,10 @@ static char *strip_spaces(char *name)
        char *p, *q;
        /* Skip over leading spaces */
        p = name;
-       while(*p && isspace(*p)) p++;
+       while(*p && isspace((unsigned char)*p)) p++;
        if(!*p) return NULL;
        q = p + strlen(p) - 1;
-       while((q != p) && isspace(*q)) q--;
+       while((q != p) && isspace((unsigned char)*q)) q--;
        if(p != q) q[1] = 0;
        if(!*p) return NULL;
        return p;
@@ -322,8 +349,9 @@ static char *strip_spaces(char *name)
 
 /* hex string utilities */
 
-/* Given a buffer of length 'len' return a Malloc'ed string with its
+/* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its
  * hex representation
+ * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines)
  */
 
 char *hex_to_string(unsigned char *buffer, long len)
@@ -333,7 +361,7 @@ char *hex_to_string(unsigned char *buffer, long len)
        int i;
        static char hexdig[] = "0123456789ABCDEF";
        if(!buffer || !len) return NULL;
-       if(!(tmp = Malloc(len * 3 + 1))) {
+       if(!(tmp = OPENSSL_malloc(len * 3 + 1))) {
                X509V3err(X509V3_F_HEX_TO_STRING,ERR_R_MALLOC_FAILURE);
                return NULL;
        }
@@ -344,6 +372,10 @@ char *hex_to_string(unsigned char *buffer, long len)
                *q++ = ':';
        }
        q[-1] = 0;
+#ifdef CHARSET_EBCDIC
+       ebcdic2ascii(tmp, tmp, q - tmp - 1);
+#endif
+
        return tmp;
 }
 
@@ -359,14 +391,20 @@ unsigned char *string_to_hex(char *str, long *len)
                X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_INVALID_NULL_ARGUMENT);
                return NULL;
        }
-       if(!(hexbuf = Malloc(strlen(str) >> 1))) goto err;
+       if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err;
        for(p = (unsigned char *)str, q = hexbuf; *p;) {
                ch = *p++;
+#ifdef CHARSET_EBCDIC
+               ch = os_toebcdic[ch];
+#endif
                if(ch == ':') continue;
                cl = *p++;
+#ifdef CHARSET_EBCDIC
+               cl = os_toebcdic[cl];
+#endif
                if(!cl) {
                        X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ODD_NUMBER_OF_DIGITS);
-                       Free(hexbuf);
+                       OPENSSL_free(hexbuf);
                        return NULL;
                }
                if(isupper(ch)) ch = tolower(ch);
@@ -388,12 +426,12 @@ unsigned char *string_to_hex(char *str, long *len)
        return hexbuf;
 
        err:
-       if(hexbuf) Free(hexbuf);
+       if(hexbuf) OPENSSL_free(hexbuf);
        X509V3err(X509V3_F_STRING_TO_HEX,ERR_R_MALLOC_FAILURE);
        return NULL;
 
        badhex:
-       Free(hexbuf);
+       OPENSSL_free(hexbuf);
        X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ILLEGAL_HEX_DIGIT);
        return NULL;
 
@@ -413,3 +451,86 @@ int name_cmp(const char *name, const char *cmp)
        if(!c || (c=='.')) return 0;
        return 1;
 }
+
+static int sk_strcmp(const char * const *a, const char * const *b)
+{
+       return strcmp(*a, *b);
+}
+
+STACK *X509_get1_email(X509 *x)
+{
+       GENERAL_NAMES *gens;
+       STACK *ret;
+       gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+       ret = get_email(X509_get_subject_name(x), gens);
+       sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+       return ret;
+}
+
+STACK *X509_REQ_get1_email(X509_REQ *x)
+{
+       GENERAL_NAMES *gens;
+       STACK_OF(X509_EXTENSION) *exts;
+       STACK *ret;
+       exts = X509_REQ_get_extensions(x);
+       gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL);
+       ret = get_email(X509_REQ_get_subject_name(x), gens);
+       sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+       sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+       return ret;
+}
+
+
+static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens)
+{
+       STACK *ret = NULL;
+       X509_NAME_ENTRY *ne;
+       ASN1_IA5STRING *email;
+       GENERAL_NAME *gen;
+       int i;
+       /* Now add any email address(es) to STACK */
+       i = -1;
+       /* First supplied X509_NAME */
+       while((i = X509_NAME_get_index_by_NID(name,
+                                        NID_pkcs9_emailAddress, i)) >= 0) {
+               ne = X509_NAME_get_entry(name, i);
+               email = X509_NAME_ENTRY_get_data(ne);
+               if(!append_ia5(&ret, email)) return NULL;
+       }
+       for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+       {
+               gen = sk_GENERAL_NAME_value(gens, i);
+               if(gen->type != GEN_EMAIL) continue;
+               if(!append_ia5(&ret, gen->d.ia5)) return NULL;
+       }
+       return ret;
+}
+
+static void str_free(void *str)
+{
+       OPENSSL_free(str);
+}
+
+static int append_ia5(STACK **sk, ASN1_IA5STRING *email)
+{
+       char *emtmp;
+       /* First some sanity checks */
+       if(email->type != V_ASN1_IA5STRING) return 1;
+       if(!email->data || !email->length) return 1;
+       if(!*sk) *sk = sk_new(sk_strcmp);
+       if(!*sk) return 0;
+       /* Don't add duplicates */
+       if(sk_find(*sk, (char *)email->data) != -1) return 1;
+       emtmp = BUF_strdup((char *)email->data);
+       if(!emtmp || !sk_push(*sk, emtmp)) {
+               X509_email_free(*sk);
+               *sk = NULL;
+               return 0;
+       }
+       return 1;
+}
+
+void X509_email_free(STACK *sk)
+{
+       sk_pop_free(sk, str_free);
+}