in projects/linux/asn1/x509_openssl.c [555:752]
static int x509_openssl_create_certificate (struct x509_certificate *cert, EVP_PKEY *cert_key,
enum hash_type sig_hash, const uint8_t *serial_num, size_t serial_length, const char *name,
int type, EVP_PKEY *ca_key, const struct x509_certificate *ca_cert,
const struct x509_extension_builder *const *extra_extensions, size_t ext_count)
{
X509 *x509;
X509 *ca_x509;
BIGNUM *serial;
X509_NAME *subject;
ASN1_TIME *validity;
const EVP_MD *hash_algo;
char *key_usage;
size_t i;
int status;
switch (sig_hash) {
case HASH_TYPE_SHA256:
hash_algo = EVP_sha256 ();
break;
#ifdef HASH_ENABLE_SHA384
case HASH_TYPE_SHA384:
hash_algo = EVP_sha384 ();
break;
#endif
#ifdef HASH_ENABLE_SHA512
case HASH_TYPE_SHA512:
hash_algo = EVP_sha512 ();
break;
#endif
default:
return X509_ENGINE_UNSUPPORTED_SIG_HASH;
}
ERR_clear_error ();
x509 = X509_new ();
if (x509 == NULL) {
status = -ERR_get_error ();
goto err_cert;
}
if (ca_key) {
ca_x509 = (X509*) ca_cert->context;
}
else {
ca_x509 = x509;
}
status = X509_set_pubkey (x509, cert_key);
if (status == 0) {
status = -ERR_get_error ();
goto err_req_key;
}
status = X509_set_version (x509, 2);
if (status == 0) {
status = -ERR_get_error ();
goto err_req_key;
}
serial = BN_bin2bn (serial_num, serial_length, NULL);
if (serial == NULL) {
status = -ERR_get_error ();
goto err_serial;
}
if (BN_is_zero (serial)) {
status = X509_ENGINE_INVALID_SERIAL_NUM;
goto err_serial;
}
if (BN_to_ASN1_INTEGER (serial, X509_get_serialNumber (x509)) == NULL) {
status = -ERR_get_error ();
goto err_serial;
}
subject = X509_get_subject_name (x509);
status = X509_NAME_add_entry_by_txt (subject, "CN", MBSTRING_ASC, (unsigned char*) name,
-1, -1, 0);
if (status == 0) {
status = -ERR_get_error ();
goto err_serial;
}
subject = X509_get_subject_name (ca_x509);
status = X509_set_issuer_name (x509, subject);
if (status == 0) {
status = -ERR_get_error ();
goto err_serial;
}
validity = X509_get_notBefore (x509);
status = ASN1_TIME_set_string (validity, "180101000000Z");
if (status == 0) {
status = -ERR_get_error ();
goto err_serial;
}
validity = X509_get_notAfter (x509);
status = ASN1_TIME_set_string (validity, "99991231235959Z");
if (status == 0) {
status = -ERR_get_error ();
goto err_serial;
}
status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_subject_key_identifier,
"hash");
if (status != 0) {
goto err_serial;
}
status = x509_openssl_add_standard_v3_extension (x509, ca_x509,
NID_authority_key_identifier, "keyid:always");
if (status != 0) {
goto err_serial;
}
if (type) {
key_usage = "critical,keyCertSign";
}
else {
key_usage = "critical,digitalSignature,keyAgreement";
}
status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_key_usage, key_usage);
if (status != 0) {
goto err_serial;
}
if (type == X509_CERT_END_ENTITY) {
status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_ext_key_usage,
"critical,clientAuth");
if (status != 0) {
goto err_serial;
}
}
if (type) {
char constraint[35];
if (X509_CERT_PATHLEN (type) <= X509_CERT_MAX_PATHLEN) {
sprintf (constraint, "critical,CA:TRUE,pathlen:%d", X509_CERT_PATHLEN (type));
}
else {
strcpy (constraint, "critical,CA:TRUE");
}
status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_basic_constraints,
constraint);
if (status != 0) {
goto err_serial;
}
}
for (i = 0; i < ext_count; i++) {
X509_EXTENSION *ext;
ASN1_OCTET_STRING *ext_data;
if (extra_extensions[i] != NULL) {
status = x509_openssl_create_custom_extension (extra_extensions[i], &ext, &ext_data);
if (status != 0) {
goto err_serial;
}
status = x509_openssl_add_custom_v3_extension (x509, ext, ext_data);
if (status != 0) {
goto err_serial;
}
}
}
if (ca_key) {
status = X509_sign (x509, ca_key, hash_algo);
}
else {
status = X509_sign (x509, cert_key, hash_algo);
}
if (status == 0) {
status = -ERR_get_error ();
goto err_serial;
}
cert->context = x509;
status = 0;
err_serial:
BN_free (serial);
err_req_key:
if (status != 0) {
X509_free (x509);
}
err_cert:
return status;
}