/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
#include "internal/x509_int.h"
static void x509v3_cache_extensions(X509 *x);
static int check_ssl_ca(const X509 *x);
static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int purpose_smime(const X509 *x, int ca);
static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b);
static void xptable_free(X509_PURPOSE *p);
static X509_PURPOSE xstandard[] = {
{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_COMPAT, 0, check_purpose_crl_sign,
"CRL signing", "crlsign", NULL},
{X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any",
NULL},
{X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper,
"OCSP helper", "ocsphelper", NULL},
{X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0,
check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign",
NULL},
};
#define X509_PURPOSE_COUNT OSSL_NELEM(xstandard)
static STACK_OF(X509_PURPOSE) *xptable = NULL;
static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b)
{
return (*a)->purpose - (*b)->purpose;
}
/*
* As much as I'd like to make X509_check_purpose use a "const" X509* I
* really can't because it does recalculate hashes and do other non-const
* things.
*/
int X509_check_purpose(X509 *x, int id, int ca)
{
int idx;
const X509_PURPOSE *pt;
if (!(x->ex_flags & EXFLAG_SET)) {
CRYPTO_THREAD_write_lock(x->lock);
x509v3_cache_extensions(x);
CRYPTO_THREAD_unlock(x->lock);
}
/* Return if side-effect only call */
if (id == -1)
return 1;
idx = X509_PURPOSE_get_by_id(id);
if (idx == -1)
return -1;
pt = X509_PURPOSE_get0(idx);
return pt->check_purpose(pt, x, ca);
}
int X509_PURPOSE_set(int *p, int purpose)
{
if (X509_PURPOSE_get_by_id(purpose) == -1) {
X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE);
return 0;
}
*p = purpose;
return 1;
}
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_get0(int idx)
{
if (idx < 0)
return NULL;
if (idx < (int)X509_PURPOSE_COUNT)
return xstandard + idx;
return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
}
int X509_PU