Fix a bug in the modified purpose code: it wasn't updated to use the
[openssl.git] / crypto / x509v3 / v3_purp.c
index 6ec5f957e9408053ae3fbd9f14afbd07dd626291..c5fca40c4c03e0e358db1d2596220c2da65e003e 100644 (file)
@@ -61,7 +61,6 @@
 #include <openssl/x509v3.h>
 
 
-static int x509_purpose_get_idx(int id);
 static void x509v3_cache_extensions(X509 *x);
 
 static int ca_check(X509 *x);
@@ -74,24 +73,26 @@ static int check_purpose_smime_encrypt(X509_PURPOSE *xp, X509 *x, int ca);
 static int check_purpose_crl_sign(X509_PURPOSE *xp, X509 *x, int ca);
 
 static int xp_cmp(X509_PURPOSE **a, X509_PURPOSE **b);
+static void xptable_free(X509_PURPOSE *p);
 
 static X509_PURPOSE xstandard[] = {
-       {1, 0, check_purpose_ssl_client, "SSL client", /* NULL */},
-       {2, 0, check_purpose_ssl_server, "SSL server", /* NULL */},
-       {3, 0, check_purpose_ns_ssl_server, "Netscape SSL server", /* NULL */},
-       {4, 0, check_purpose_smime_sign, "S/MIME signing", /* NULL */},
-       {5, 0, check_purpose_smime_encrypt, "S/MIME encryption", /* NULL */},
-       {6, 0, check_purpose_crl_sign, "CRL signing", /* NULL */},
-       {-1, 0, NULL, NULL, /* NULL */}
+       {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL},
+       {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, "SSL server", "sslserver", NULL},
+       {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
+       {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "smimesign", NULL},
+       {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
+       {X509_PURPOSE_CRL_SIGN, X509_TRUST_ANY, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
 };
 
+#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
+
 IMPLEMENT_STACK_OF(X509_PURPOSE)
 
 static STACK_OF(X509_PURPOSE) *xptable = NULL;
 
 static int xp_cmp(X509_PURPOSE **a, X509_PURPOSE **b)
 {
-       return (*a)->purpose_id - (*b)->purpose_id;
+       return (*a)->purpose - (*b)->purpose;
 }
 
 int X509_check_purpose(X509 *x, int id, int ca)
@@ -104,92 +105,146 @@ int X509_check_purpose(X509 *x, int id, int ca)
                CRYPTO_w_unlock(CRYPTO_LOCK_X509);
        }
        if(id == -1) return 1;
-       idx = x509_purpose_get_idx(id);
+       idx = X509_PURPOSE_get_by_id(id);
        if(idx == -1) return -1;
-       pt = sk_X509_PURPOSE_value(xptable, idx);
-       return pt->check_purpose(pt, x,ca);
+       pt = X509_PURPOSE_iget(idx);
+       return pt->check_purpose(pt, x, ca);
+}
+
+int X509_PURPOSE_get_count(void)
+{
+       if(!xptable) return X509_PURPOSE_COUNT;
+       return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
 }
 
+X509_PURPOSE * X509_PURPOSE_iget(int idx)
+{
+       if(idx < 0) return NULL;
+       if(idx < X509_PURPOSE_COUNT) return xstandard + idx;
+       return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
+}
 
+int X509_PURPOSE_get_by_sname(char *sname)
+{
+       int i;
+       X509_PURPOSE *xptmp;
+       for(i = 0; i < X509_PURPOSE_get_count(); i++) {
+               xptmp = X509_PURPOSE_iget(i);
+               if(!strcmp(xptmp->sname, sname)) return i;
+       }
+       return -1;
+}
 
 
-static int x509_purpose_get_idx(int id)
+int X509_PURPOSE_get_by_id(int purpose)
 {
        X509_PURPOSE tmp;
-       tmp.purpose_id = id;
+       int idx;
+       if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
+               return purpose - X509_PURPOSE_MIN;
+       tmp.purpose = purpose;
        if(!xptable) return -1;
-       return sk_X509_PURPOSE_find(xptable, &tmp);
+       idx = sk_X509_PURPOSE_find(xptable, &tmp);
+       if(idx == -1) return -1;
+       return idx + X509_PURPOSE_COUNT;
 }
 
-int X509_PURPOSE_add(X509_PURPOSE *xp)
+int X509_PURPOSE_add(int id, int trust, int flags,
+                       int (*ck)(X509_PURPOSE *, X509 *, int),
+                                       char *name, char *sname, void *arg)
 {
        int idx;
-       if(!xptable)
-               {
-               xptable = sk_X509_PURPOSE_new(xp_cmp);
-               if (!xptable) 
-                       {
+       X509_PURPOSE *ptmp;
+       /* This is set according to what we change: application can't set it */
+       flags &= ~X509_PURPOSE_DYNAMIC;
+       /* This will always be set for application modified trust entries */
+       flags |= X509_PURPOSE_DYNAMIC_NAME;
+       /* Get existing entry if any */
+       idx = X509_PURPOSE_get_by_id(id);
+       /* Need a new entry */
+       if(idx == -1) {
+               if(!(ptmp = Malloc(sizeof(X509_PURPOSE)))) {
                        X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
                        return 0;
-                       }
                }
-                       
-       idx = x509_purpose_get_idx(xp->purpose_id);
-       if(idx != -1)
-               sk_X509_PURPOSE_set(xptable, idx, xp);
-       else
-               if (!sk_X509_PURPOSE_push(xptable, xp))
-                       {
+               ptmp->flags = X509_PURPOSE_DYNAMIC;
+       } else ptmp = X509_PURPOSE_iget(idx);
+
+       /* Free existing name if dynamic */
+       if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
+               Free(ptmp->name);
+               Free(ptmp->sname);
+       }
+       /* dup supplied name */
+       ptmp->name = BUF_strdup(name);
+       ptmp->sname = BUF_strdup(sname);
+       if(!ptmp->name || !ptmp->sname) {
+               X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
+               return 0;
+       }
+       /* Keep the dynamic flag of existing entry */
+       ptmp->flags &= X509_PURPOSE_DYNAMIC;
+       /* Set all other flags */
+       ptmp->flags |= flags;
+
+       ptmp->purpose = id;
+       ptmp->trust = trust;
+       ptmp->check_purpose = ck;
+       ptmp->usr_data = arg;
+
+       /* If its a new entry manage the dynamic table */
+       if(idx == -1) {
+               if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
                        X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
                        return 0;
-                       }
+               }
+               if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
+                       X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
+                       return 0;
+               }
+       }
        return 1;
 }
 
 static void xptable_free(X509_PURPOSE *p)
        {
-       if (p->purpose_flags & X509_PURPOSE_DYNAMIC) 
+       if(!p) return;
+       if (p->flags & X509_PURPOSE_DYNAMIC) 
                {
-               if (p->purpose_flags & X509_PURPOSE_DYNAMIC_NAME)
-                       Free(p->purpose_name);
+               if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
+                       Free(p->name);
+                       Free(p->sname);
+               }
                Free(p);
                }
        }
 
 void X509_PURPOSE_cleanup(void)
 {
+       int i;
        sk_X509_PURPOSE_pop_free(xptable, xptable_free);
+       for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i);
        xptable = NULL;
 }
 
-void X509_PURPOSE_add_standard(void)
+int X509_PURPOSE_get_id(X509_PURPOSE *xp)
 {
-       X509_PURPOSE *xp;
-       for(xp = xstandard; xp->purpose_name; xp++)
-               X509_PURPOSE_add(xp);
+       return xp->purpose;
 }
 
-int X509_PURPOSE_enum(int (*efunc)(X509_PURPOSE *, void *), void *usr)
+char *X509_PURPOSE_iget_name(X509_PURPOSE *xp)
 {
-       int i;
-       X509_PURPOSE *xp;
-       if(!xptable) return 0;
-       for(i = 0; i < sk_X509_PURPOSE_num(xptable); i++) {
-               xp = sk_X509_PURPOSE_value(xptable, i);
-               if(!efunc(xp, usr)) return i;
-       }
-       return i;
+       return xp->name;
 }
 
-
-int X509_PURPOSE_get_id(X509_PURPOSE *xp)
+char *X509_PURPOSE_iget_sname(X509_PURPOSE *xp)
 {
-       return xp->purpose_id;
+       return xp->sname;
 }
 
-char *X509_PURPOSE_get_name(X509_PURPOSE *xp)
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
 {
-       return xp->purpose_name;
+       return xp->trust;
 }
 
 static void x509v3_cache_extensions(X509 *x)
@@ -202,7 +257,7 @@ static void x509v3_cache_extensions(X509 *x)
        if(x->ex_flags & EXFLAG_SET) return;
        X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
        /* Does subject name match issuer ? */
-       if(X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
+       if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
                         x->ex_flags |= EXFLAG_SS;
        /* V1 should mean no extensions ... */
        if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;