Make X509_ATTRIBUTE opaque.
authorDr. Stephen Henson <steve@openssl.org>
Sat, 14 Mar 2015 23:48:47 +0000 (23:48 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Mon, 16 Mar 2015 15:54:19 +0000 (15:54 +0000)
Reviewed-by: Rich Salz <rsalz@openssl.org>
12 files changed:
apps/pkcs12.c
crypto/asn1/Makefile
crypto/asn1/t_req.c
crypto/asn1/x_attrib.c [deleted file]
crypto/pkcs12/p12_attr.c
crypto/pkcs7/pk7_doit.c
crypto/x509/Makefile
crypto/x509/x509.h
crypto/x509/x509_att.c
crypto/x509/x509_lcl.h
crypto/x509/x509_req.c
crypto/x509/x_attrib.c [new file with mode: 0644]

index 3c06930ce60451fb0fcbeda59abe457728f4a3a6..e33fe243eed353da077a5aa89c9717536d88fd5f 100644 (file)
@@ -993,17 +993,19 @@ int print_attribs(BIO *out, STACK_OF(X509_ATTRIBUTE) *attrlst,
     }
     BIO_printf(out, "%s\n", name);
     for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) {
+        ASN1_OBJECT *attr_obj;
         attr = sk_X509_ATTRIBUTE_value(attrlst, i);
-        attr_nid = OBJ_obj2nid(attr->object);
+        attr_obj = X509_ATTRIBUTE_get0_object(attr);
+        attr_nid = OBJ_obj2nid(attr_obj);
         BIO_printf(out, "    ");
         if (attr_nid == NID_undef) {
-            i2a_ASN1_OBJECT(out, attr->object);
+            i2a_ASN1_OBJECT(out, attr_obj);
             BIO_printf(out, ": ");
         } else
             BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid));
 
-        if (sk_ASN1_TYPE_num(attr->value.set)) {
-            av = sk_ASN1_TYPE_value(attr->value.set, 0);
+        if (X509_ATTRIBUTE_count(attr)) {
+            av = X509_ATTRIBUTE_get0_type(attr, 0);
             switch (av->type) {
             case V_ASN1_BMPSTRING:
                 value = OPENSSL_uni2asc(av->value.bmpstring->data,
index a7b6c353965f9c47f60c9e7b763e139c9ef26948..3009bbf1983a4e7c63e5f59346b695e3c8047786 100644 (file)
@@ -20,7 +20,7 @@ LIB=$(TOP)/libcrypto.a
 LIBSRC=        a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \
        a_print.c a_type.c a_set.c a_dup.c a_d2i_fp.c a_i2d_fp.c \
        a_enum.c a_utf8.c a_sign.c a_digest.c a_verify.c a_mbstr.c a_strex.c \
-       x_algor.c x_val.c x_pubkey.c x_sig.c x_req.c x_attrib.c x_bignum.c \
+       x_algor.c x_val.c x_pubkey.c x_sig.c x_req.c x_bignum.c \
        x_long.c x_name.c x_x509.c x_x509a.c x_crl.c x_info.c x_spki.c nsseq.c \
        x_nx509.c d2i_pu.c d2i_pr.c i2d_pu.c i2d_pr.c\
        t_req.c t_x509.c t_x509a.c t_crl.c t_pkey.c t_spki.c t_bitst.c \
@@ -34,7 +34,7 @@ LIBSRC=       a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \
 LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \
        a_print.o a_type.o a_set.o a_dup.o a_d2i_fp.o a_i2d_fp.o \
        a_enum.o a_utf8.o a_sign.o a_digest.o a_verify.o a_mbstr.o a_strex.o \
-       x_algor.o x_val.o x_pubkey.o x_sig.o x_req.o x_attrib.o x_bignum.o \
+       x_algor.o x_val.o x_pubkey.o x_sig.o x_req.o x_bignum.o \
        x_long.o x_name.o x_x509.o x_x509a.o x_crl.o x_info.o x_spki.o nsseq.o \
        x_nx509.o d2i_pu.o d2i_pr.o i2d_pu.o i2d_pr.o \
        t_req.o t_x509.o t_x509a.o t_crl.o t_pkey.o t_spki.o t_bitst.o \
@@ -759,19 +759,6 @@ x_algor.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h
 x_algor.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
 x_algor.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
 x_algor.o: ../../include/openssl/x509_vfy.h x_algor.c
-x_attrib.o: ../../e_os.h ../../include/openssl/asn1.h
-x_attrib.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
-x_attrib.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h
-x_attrib.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
-x_attrib.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h
-x_attrib.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-x_attrib.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
-x_attrib.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
-x_attrib.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-x_attrib.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h
-x_attrib.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
-x_attrib.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
-x_attrib.o: ../../include/openssl/x509_vfy.h ../cryptlib.h x_attrib.c
 x_bignum.o: ../../e_os.h ../../include/openssl/asn1.h
 x_bignum.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
 x_bignum.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
index 58986e11388b7220bbcebbed24bd5ad0d2f93e59..2a8895834b70ab0dccca2131c6aa2970790a3c8d 100644 (file)
@@ -161,27 +161,22 @@ int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags,
                 ASN1_TYPE *at;
                 X509_ATTRIBUTE *a;
                 ASN1_BIT_STRING *bs = NULL;
-                ASN1_TYPE *t;
+                ASN1_OBJECT *aobj;
                 int j, type = 0, count = 1, ii = 0;
 
                 a = sk_X509_ATTRIBUTE_value(sk, i);
-                if (X509_REQ_extension_nid(OBJ_obj2nid(a->object)))
+                aobj = X509_ATTRIBUTE_get0_object(a);
+                if (X509_REQ_extension_nid(OBJ_obj2nid(aobj)))
                     continue;
                 if (BIO_printf(bp, "%12s", "") <= 0)
                     goto err;
-                if ((j = i2a_ASN1_OBJECT(bp, a->object)) > 0) {
-                    if (a->single) {
-                        t = a->value.single;
-                        type = t->type;
-                        bs = t->value.bit_string;
-                    } else {
-                        ii = 0;
-                        count = sk_ASN1_TYPE_num(a->value.set);
+                if ((j = i2a_ASN1_OBJECT(bp, aobj)) > 0) {
+                    ii = 0;
+                    count = X509_ATTRIBUTE_count(a);
  get_next:
-                        at = sk_ASN1_TYPE_value(a->value.set, ii);
-                        type = at->type;
-                        bs = at->value.asn1_string;
-                    }
+                    at = X509_ATTRIBUTE_get0_type(a, ii);
+                    type = at->type;
+                    bs = at->value.asn1_string;
                 }
                 for (j = 25 - j; j > 0; j--)
                     if (BIO_write(bp, " ", 1) != 1)
diff --git a/crypto/asn1/x_attrib.c b/crypto/asn1/x_attrib.c
deleted file mode 100644 (file)
index 93ef53b..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* crypto/asn1/x_attrib.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "cryptlib.h"
-#include <openssl/objects.h>
-#include <openssl/asn1t.h>
-#include <openssl/x509.h>
-
-/*-
- * X509_ATTRIBUTE: this has the following form:
- *
- * typedef struct x509_attributes_st
- *      {
- *      ASN1_OBJECT *object;
- *      int single;
- *      union   {
- *              char            *ptr;
- *              STACK_OF(ASN1_TYPE) *set;
- *              ASN1_TYPE       *single;
- *              } value;
- *      } X509_ATTRIBUTE;
- *
- * this needs some extra thought because the CHOICE type is
- * merged with the main structure and because the value can
- * be anything at all we *must* try the SET OF first because
- * the ASN1_ANY type will swallow anything including the whole
- * SET OF structure.
- */
-
-ASN1_CHOICE(X509_ATTRIBUTE_SET) = {
-        ASN1_SET_OF(X509_ATTRIBUTE, value.set, ASN1_ANY),
-        ASN1_SIMPLE(X509_ATTRIBUTE, value.single, ASN1_ANY)
-} ASN1_CHOICE_END_selector(X509_ATTRIBUTE, X509_ATTRIBUTE_SET, single)
-
-ASN1_SEQUENCE(X509_ATTRIBUTE) = {
-        ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT),
-        /* CHOICE type merged with parent */
-        ASN1_EX_COMBINE(0, 0, X509_ATTRIBUTE_SET)
-} ASN1_SEQUENCE_END(X509_ATTRIBUTE)
-
-IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE)
-IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE)
-
-X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value)
-{
-    X509_ATTRIBUTE *ret = NULL;
-    ASN1_TYPE *val = NULL;
-
-    if ((ret = X509_ATTRIBUTE_new()) == NULL)
-        return (NULL);
-    ret->object = OBJ_nid2obj(nid);
-    ret->single = 0;
-    if ((ret->value.set = sk_ASN1_TYPE_new_null()) == NULL)
-        goto err;
-    if ((val = ASN1_TYPE_new()) == NULL)
-        goto err;
-    if (!sk_ASN1_TYPE_push(ret->value.set, val))
-        goto err;
-
-    ASN1_TYPE_set(val, atrtype, value);
-    return (ret);
- err:
-    if (ret != NULL)
-        X509_ATTRIBUTE_free(ret);
-    if (val != NULL)
-        ASN1_TYPE_free(val);
-    return (NULL);
-}
index fff3ba1ece7f5d5e3e8d5040b47ba04775d55ad0..70695b7bb6844e2f869b05265dccedf43bf65f05 100644 (file)
@@ -121,18 +121,9 @@ ASN1_TYPE *PKCS12_get_attr_gen(STACK_OF(X509_ATTRIBUTE) *attrs, int attr_nid)
 {
     X509_ATTRIBUTE *attrib;
     int i;
-    if (!attrs)
-        return NULL;
-    for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) {
-        attrib = sk_X509_ATTRIBUTE_value(attrs, i);
-        if (OBJ_obj2nid(attrib->object) == attr_nid) {
-            if (sk_ASN1_TYPE_num(attrib->value.set))
-                return sk_ASN1_TYPE_value(attrib->value.set, 0);
-            else
-                return NULL;
-        }
-    }
-    return NULL;
+    i = X509at_get_attr_by_NID(attrs, attr_nid, -1);
+    attrib = X509at_get_attr(attrs, i);
+    return X509_ATTRIBUTE_get0_type(attrib, 0);
 }
 
 char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag)
index 54b7b0785ab62b3dd4293bac78d8cd1306eebfc4..f61d63b39b3a28ae66015925e1056b9ebda7caa9 100644 (file)
@@ -1067,23 +1067,11 @@ ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid)
 
 static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid)
 {
-    int i;
+    int idx;
     X509_ATTRIBUTE *xa;
-    ASN1_OBJECT *o;
-
-    o = OBJ_nid2obj(nid);
-    if (!o || !sk)
-        return (NULL);
-    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
-        xa = sk_X509_ATTRIBUTE_value(sk, i);
-        if (OBJ_cmp(xa->object, o) == 0) {
-            if (!xa->single && sk_ASN1_TYPE_num(xa->value.set))
-                return (sk_ASN1_TYPE_value(xa->value.set, 0));
-            else
-                return (NULL);
-        }
-    }
-    return (NULL);
+    idx = X509at_get_attr_by_NID(sk, nid, -1);
+    xa = X509at_get_attr(sk, idx);
+    return X509_ATTRIBUTE_get0_type(xa, 0);
 }
 
 ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
@@ -1167,7 +1155,7 @@ static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
 
         for (i = 0; i < sk_X509_ATTRIBUTE_num(*sk); i++) {
             attr = sk_X509_ATTRIBUTE_value(*sk, i);
-            if (OBJ_obj2nid(attr->object) == nid) {
+            if (OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)) == nid) {
                 X509_ATTRIBUTE_free(attr);
                 attr = X509_ATTRIBUTE_create(nid, atrtype, value);
                 if (attr == NULL)
index f168b473e792bbc5050114bd2c9a5311ca6ebf96..de964059fccfef889ab40cebd3ece59772d53604 100644 (file)
@@ -22,13 +22,13 @@ LIBSRC=     x509_def.c x509_d2.c x509_r2x.c x509_cmp.c \
        x509_set.c x509cset.c x509rset.c x509_err.c \
        x509name.c x509_v3.c x509_ext.c x509_att.c \
        x509type.c x509_lu.c x_all.c x509_txt.c \
-       x509_trs.c by_file.c by_dir.c x509_vpm.c
+       x509_trs.c by_file.c by_dir.c x509_vpm.c x_attrib.c
 LIBOBJ= x509_def.o x509_d2.o x509_r2x.o x509_cmp.o \
        x509_obj.o x509_req.o x509spki.o x509_vfy.o \
        x509_set.o x509cset.o x509rset.o x509_err.o \
        x509name.o x509_v3.o x509_ext.o x509_att.o \
        x509type.o x509_lu.o x_all.o x509_txt.o \
-       x509_trs.o by_file.o by_dir.o x509_vpm.o
+       x509_trs.o by_file.o by_dir.o x509_vpm.o x_attrib.o
 
 SRC= $(LIBSRC)
 
index afc16a318734142f3e62b5048c324764a76e3640..64f1283e425a82ff621416cb3cd90e97fb8ea5f4 100644 (file)
@@ -181,21 +181,7 @@ typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
 
 DECLARE_STACK_OF(X509_EXTENSION)
 
-/* a sequence of these are used */
-typedef struct x509_attributes_st {
-    ASN1_OBJECT *object;
-    int single;                 /* 0 for a set, 1 for a single item (which is
-                                 * wrong) */
-    union {
-        char *ptr;
-        /*
-         * 0
-         */ STACK_OF(ASN1_TYPE) *set;
-        /*
-         * 1
-         */ ASN1_TYPE *single;
-    } value;
-} X509_ATTRIBUTE;
+typedef struct x509_attributes_st X509_ATTRIBUTE;
 
 DECLARE_STACK_OF(X509_ATTRIBUTE)
 
index bd59281f9dac62a909b6002ef6fcd5915fbf45dc..212c422e0567f04f7e2cdb6a386bc2074550e5cd 100644 (file)
@@ -64,6 +64,7 @@
 #include <openssl/evp.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
+#include "x509_lcl.h"
 
 int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
 {
index c7621fd1e614906ff182d2b96e10c1de0ef5dff8..15b861809b652e12151ccab3a6c65ea26fc72548 100644 (file)
@@ -70,3 +70,19 @@ struct X509_VERIFY_PARAM_ID_st {
 };
 
 int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet);
+
+/* a sequence of these are used */
+struct x509_attributes_st {
+    ASN1_OBJECT *object;
+    int single;                 /* 0 for a set, 1 for a single item (which is
+                                 * wrong) */
+    union {
+        char *ptr;
+        /*
+         * 0
+         */ STACK_OF(ASN1_TYPE) *set;
+        /*
+         * 1
+         */ ASN1_TYPE *single;
+    } value;
+};
index 01795f4b3f370eb7300986b06df9c98de96c2221..682c2c2acbaead9faf786b00d8ac2f79ebebc4f5 100644 (file)
@@ -201,10 +201,7 @@ STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
         if (idx == -1)
             continue;
         attr = X509_REQ_get_attr(req, idx);
-        if (attr->single)
-            ext = attr->value.single;
-        else if (sk_ASN1_TYPE_num(attr->value.set))
-            ext = sk_ASN1_TYPE_value(attr->value.set, 0);
+        ext = X509_ATTRIBUTE_get0_type(attr, 0);
         break;
     }
     if (!ext || (ext->type != V_ASN1_SEQUENCE))
@@ -223,37 +220,17 @@ STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
 int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
                                 int nid)
 {
-    ASN1_TYPE *at = NULL;
-    X509_ATTRIBUTE *attr = NULL;
-    if (!(at = ASN1_TYPE_new()) || !(at->value.sequence = ASN1_STRING_new()))
-        goto err;
-
-    at->type = V_ASN1_SEQUENCE;
+    int extlen;
+    int rv = 0;
+    unsigned char *ext = NULL;
     /* Generate encoding of extensions */
-    at->value.sequence->length =
-        ASN1_item_i2d((ASN1_VALUE *)exts,
-                      &at->value.sequence->data,
-                      ASN1_ITEM_rptr(X509_EXTENSIONS));
-    if (!(attr = X509_ATTRIBUTE_new()))
-        goto err;
-    if (!(attr->value.set = sk_ASN1_TYPE_new_null()))
-        goto err;
-    if (!sk_ASN1_TYPE_push(attr->value.set, at))
-        goto err;
-    at = NULL;
-    attr->single = 0;
-    attr->object = OBJ_nid2obj(nid);
-    if (!req->req_info->attributes) {
-        if (!(req->req_info->attributes = sk_X509_ATTRIBUTE_new_null()))
-            goto err;
-    }
-    if (!sk_X509_ATTRIBUTE_push(req->req_info->attributes, attr))
-        goto err;
-    return 1;
- err:
-    X509_ATTRIBUTE_free(attr);
-    ASN1_TYPE_free(at);
-    return 0;
+    extlen = ASN1_item_i2d((ASN1_VALUE *)exts, &ext,
+                           ASN1_ITEM_rptr(X509_EXTENSIONS));
+    if (extlen <= 0)
+        return 0;
+    rv = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext, extlen);
+    OPENSSL_free(ext);
+    return rv;
 }
 
 /* This is the normal usage: use the "official" OID */
diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c
new file mode 100644 (file)
index 0000000..335a85b
--- /dev/null
@@ -0,0 +1,125 @@
+/* crypto/asn1/x_attrib.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include "x509_lcl.h"
+
+/*-
+ * X509_ATTRIBUTE: this has the following form:
+ *
+ * typedef struct x509_attributes_st
+ *      {
+ *      ASN1_OBJECT *object;
+ *      int single;
+ *      union   {
+ *              char            *ptr;
+ *              STACK_OF(ASN1_TYPE) *set;
+ *              ASN1_TYPE       *single;
+ *              } value;
+ *      } X509_ATTRIBUTE;
+ *
+ * this needs some extra thought because the CHOICE type is
+ * merged with the main structure and because the value can
+ * be anything at all we *must* try the SET OF first because
+ * the ASN1_ANY type will swallow anything including the whole
+ * SET OF structure.
+ */
+
+ASN1_CHOICE(X509_ATTRIBUTE_SET) = {
+        ASN1_SET_OF(X509_ATTRIBUTE, value.set, ASN1_ANY),
+        ASN1_SIMPLE(X509_ATTRIBUTE, value.single, ASN1_ANY)
+} ASN1_CHOICE_END_selector(X509_ATTRIBUTE, X509_ATTRIBUTE_SET, single)
+
+ASN1_SEQUENCE(X509_ATTRIBUTE) = {
+        ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT),
+        /* CHOICE type merged with parent */
+        ASN1_EX_COMBINE(0, 0, X509_ATTRIBUTE_SET)
+} ASN1_SEQUENCE_END(X509_ATTRIBUTE)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE)
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value)
+{
+    X509_ATTRIBUTE *ret = NULL;
+    ASN1_TYPE *val = NULL;
+
+    if ((ret = X509_ATTRIBUTE_new()) == NULL)
+        return (NULL);
+    ret->object = OBJ_nid2obj(nid);
+    ret->single = 0;
+    if ((ret->value.set = sk_ASN1_TYPE_new_null()) == NULL)
+        goto err;
+    if ((val = ASN1_TYPE_new()) == NULL)
+        goto err;
+    if (!sk_ASN1_TYPE_push(ret->value.set, val))
+        goto err;
+
+    ASN1_TYPE_set(val, atrtype, value);
+    return (ret);
+ err:
+    if (ret != NULL)
+        X509_ATTRIBUTE_free(ret);
+    if (val != NULL)
+        ASN1_TYPE_free(val);
+    return (NULL);
+}