Add X509V3_set_issuer_pkey, needed for AKID of self-issued not self-signed cert

Also clean up some related auxiliary functions and documentation

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13658)
master
Dr. David von Oheimb 2 years ago committed by Dr. David von Oheimb
parent ea9fd333d1
commit 41e597a01d

@ -532,6 +532,7 @@ int req_main(int argc, char **argv)
if (extensions != NULL) {
/* Check syntax of file */
X509V3_CTX ctx;
X509V3_set_ctx_test(&ctx);
X509V3_set_nconf(&ctx, req_conf);
if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) {
@ -544,6 +545,7 @@ int req_main(int argc, char **argv)
if (addext_conf != NULL) {
/* Check syntax of command line extensions */
X509V3_CTX ctx;
X509V3_set_ctx_test(&ctx);
X509V3_set_nconf(&ctx, addext_conf);
if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) {
@ -591,6 +593,7 @@ int req_main(int argc, char **argv)
if (req_exts != NULL) {
/* Check syntax of file */
X509V3_CTX ctx;
X509V3_set_ctx_test(&ctx);
X509V3_set_nconf(&ctx, req_conf);
if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) {
@ -773,7 +776,7 @@ int req_main(int argc, char **argv)
}
if (newreq || gen_x509) {
if (pkey == NULL /* can happen only if !newreq */) {
BIO_printf(bio_err, "Must provide the corresponding private key using -key\n");
BIO_printf(bio_err, "Must provide a signature key using -key\n");
goto end;
}
@ -793,7 +796,8 @@ int req_main(int argc, char **argv)
X509V3_CTX ext_ctx;
X509_NAME *issuer = CAcert != NULL ? X509_get_subject_name(CAcert) :
X509_REQ_get_subject_name(req);
X509_NAME *n_subj = X509_REQ_get_subject_name(req);
X509_NAME *n_subj = fsubj != NULL ? fsubj :
X509_REQ_get_subject_name(req);
if ((new_x509 = X509_new_ex(app_get0_libctx(),
app_get0_propq())) == NULL)
@ -823,6 +827,15 @@ int req_main(int argc, char **argv)
/* Set up V3 context struct */
X509V3_set_ctx(&ext_ctx, CAcert != NULL ? CAcert : new_x509,
new_x509, NULL, NULL, X509V3_CTX_REPLACE);
if (CAcert == NULL) { /* self-issued, possibly self-signed */
if (!X509V3_set_issuer_pkey(&ext_ctx, pkey)) /* prepare right AKID */
goto end;
ERR_set_mark();
if (!X509_check_private_key(new_x509, pkey))
BIO_printf(bio_err,
"Warning: Signature key and public key of cert do not match\n");
ERR_pop_to_mark();
}
X509V3_set_nconf(&ext_ctx, req_conf);
/* Add extensions */

@ -1079,7 +1079,13 @@ static int sign(X509 *x, EVP_PKEY *pkey, X509 *issuer,
while (X509_get_ext_count(x) > 0)
X509_delete_ext(x, 0);
}
X509V3_set_ctx(&ext_ctx, issuer, x, NULL, NULL, X509V3_CTX_REPLACE);
if (issuer == x
/* prepare the correct AKID of self-issued, possibly self-signed cert */
&& !X509V3_set_issuer_pkey(&ext_ctx, pkey))
return 0;
if (conf != NULL) {
X509V3_set_nconf(&ext_ctx, conf);
if (!X509V3_EXT_add_nconf(conf, &ext_ctx, section, x)) {
@ -1149,7 +1155,7 @@ static int print_x509v3_exts(BIO *bio, X509 *x, const char *ext_names)
exts = X509_get0_extensions(x);
if ((num = sk_X509_EXTENSION_num(exts)) <= 0) {
BIO_printf(bio, "No extensions in certificate\n");
BIO_printf(bio_err, "No extensions in certificate\n");
ret = 1;
goto end;
}

@ -13,6 +13,7 @@
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "crypto/x509.h"
#include "ext_dat.h"
static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
@ -86,7 +87,7 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
GENERAL_NAME *gen = NULL;
ASN1_INTEGER *serial = NULL;
X509_EXTENSION *ext;
X509 *cert;
X509 *issuer_cert;
AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
if (akeyid == NULL)
@ -113,36 +114,49 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
}
}
if (!ctx || !ctx->issuer_cert) {
if (ctx && (ctx->flags == CTX_TEST))
return akeyid;
if (ctx != NULL && (ctx->flags & CTX_TEST) != 0)
return akeyid;
if (ctx == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
if ((issuer_cert = ctx->issuer_cert) == NULL) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_ISSUER_CERTIFICATE);
goto err;
}
cert = ctx->issuer_cert;
if (keyid) {
i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
if ((i >= 0) && (ext = X509_get_ext(cert, i)))
if (keyid != 0) {
/* prefer any pre-existing subject key identifier of the issuer cert */
i = X509_get_ext_by_NID(issuer_cert, NID_subject_key_identifier, -1);
if (i >= 0 && (ext = X509_get_ext(issuer_cert, i)) != NULL)
ikeyid = X509V3_EXT_d2i(ext);
if (ikeyid == NULL && ctx->issuer_pkey != NULL) { /* fallback */
/* generate AKID from scratch, emulating s2i_skey_id(..., "hash") */
X509_PUBKEY *pubkey = NULL;
if (X509_PUBKEY_set(&pubkey, ctx->issuer_pkey))
ikeyid = x509_pubkey_hash(pubkey);
X509_PUBKEY_free(pubkey);
}
if ((keyid == 2 || issuer == 0)
&& (ikeyid == NULL
|| ASN1_STRING_length(ikeyid) <= 2) /* indicating "none" */ ) {
|| ASN1_STRING_length(ikeyid) <= 2) /* indicating "none" */) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
goto err;
}
}
if ((issuer && !ikeyid) || (issuer == 2)) {
isname = X509_NAME_dup(X509_get_issuer_name(cert));
serial = ASN1_INTEGER_dup(X509_get0_serialNumber(cert));
if (!isname || !serial) {
if (issuer == 2 || (issuer == 1 && ikeyid == NULL)) {
isname = X509_NAME_dup(X509_get_issuer_name(issuer_cert));
serial = ASN1_INTEGER_dup(X509_get0_serialNumber(issuer_cert));
if (isname == NULL || serial == NULL) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS);
goto err;
}
}
if (isname) {
if (isname != NULL) {
if ((gens = sk_GENERAL_NAME_new_null()) == NULL
|| (gen = GENERAL_NAME_new()) == NULL
|| !sk_GENERAL_NAME_push(gens, gen)) {

@ -325,7 +325,7 @@ static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
X509_EXTENSION *ext;
int i, num;
if (ctx && (ctx->flags == CTX_TEST))
if (ctx != NULL && (ctx->flags & CTX_TEST) != 0)
return 1;
if (!ctx || !ctx->issuer_cert) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_ISSUER_DETAILS);
@ -410,12 +410,12 @@ static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
GENERAL_NAME *gen = NULL;
int i = -1;
if (ctx != NULL && ctx->flags == CTX_TEST)
if (ctx != NULL && (ctx->flags & CTX_TEST) != 0)
return 1;
if (ctx == NULL
|| (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS);
goto err;
return 0;
}
/* Find the subject name */
if (ctx->subject_cert)

@ -437,6 +437,10 @@ static X509V3_CONF_METHOD nconf_method = {
void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
{
if (ctx == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
return;
}
ctx->db_meth = &nconf_method;
ctx->db = conf;
}
@ -444,11 +448,33 @@ void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req,
X509_CRL *crl, int flags)
{
if (ctx == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
return;
}
ctx->flags = flags;
ctx->issuer_cert = issuer;
ctx->subject_cert = subj;
ctx->crl = crl;
ctx->subject_req = req;
ctx->flags = flags;
ctx->crl = crl;
ctx->db_meth = NULL;
ctx->db = NULL;
ctx->issuer_pkey = NULL;
}
/* For API backward compatibility, this is separate from X509V3_set_ctx() */
int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey)
{
if (ctx == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ctx->subject_cert == NULL && pkey != NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
ctx->issuer_pkey = pkey;
return 1;
}
/* Old conf compatibility functions */
@ -489,6 +515,10 @@ static X509V3_CONF_METHOD conf_lhash_method = {
void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash)
{
if (ctx == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
return;
}
ctx->db_meth = &conf_lhash_method;
ctx->db = lhash;
}

@ -52,56 +52,49 @@ ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
}
static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *str)
ASN1_OCTET_STRING *x509_pubkey_hash(X509_PUBKEY *pubkey)
{
ASN1_OCTET_STRING *oct;
X509_PUBKEY *pubkey;
const unsigned char *pk;
int pklen;
unsigned char pkey_dig[EVP_MAX_MD_SIZE];
unsigned int diglen;
if (strcmp(str, "none") == 0)
return ASN1_OCTET_STRING_new(); /* dummy */
if (strcmp(str, "hash") != 0)
return s2i_ASN1_OCTET_STRING(method, ctx, str);
if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
if (pubkey == NULL) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
return NULL;
}
if ((oct = ASN1_OCTET_STRING_new()) == NULL)
return NULL;
if (ctx && (ctx->flags == CTX_TEST))
X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey);
/* TODO(3.0) - explicitly fetch the digest */
if (EVP_Digest(pk, pklen, pkey_dig, &diglen, EVP_sha1(), NULL)
&& ASN1_OCTET_STRING_set(oct, pkey_dig, diglen))
return oct;
if (!ctx || (!ctx->subject_req && !ctx->subject_cert)) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
goto err;
}
pubkey = ctx->subject_req != NULL ?
ctx->subject_req->req_info.pubkey :
ctx->subject_cert->cert_info.key;
if (pubkey == NULL) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
goto err;
}
ASN1_OCTET_STRING_free(oct);
return NULL;
}
X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey);
static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *str)
{
if (strcmp(str, "none") == 0)
return ASN1_OCTET_STRING_new(); /* dummy */
if (!EVP_Digest(pk, pklen, pkey_dig, &diglen, EVP_sha1(), NULL))
goto err;
if (strcmp(str, "hash") != 0)
return s2i_ASN1_OCTET_STRING(method, ctx /* not used */, str);
if (!ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) {
ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
goto err;
if (ctx != NULL && (ctx->flags & CTX_TEST) != 0)
return ASN1_OCTET_STRING_new();
if (ctx == NULL
|| (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS);
return NULL;
}
return oct;
err:
ASN1_OCTET_STRING_free(oct);
return NULL;
return x509_pubkey_hash(ctx->subject_req != NULL ?
ctx->subject_req->req_info.pubkey :
ctx->subject_cert->cert_info.key);
}

@ -12,7 +12,6 @@
#include <openssl/asn1.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include <crypto/x509v3.h>
#include "ext_dat.h"
/*

@ -1,46 +0,0 @@
=pod
=head1 NAME
i2s_ASN1_UTF8STRING,
s2i_ASN1_UTF8STRING
- convert objects from/to ASN.1/string representation
=head1 SYNOPSIS
#include "crypto/x509v3.h"
char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
ASN1_UTF8STRING *utf8);
ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str);
=head1 DESCRIPTION
These functions convert OpenSSL objects to and from their ASN.1/string
representation. This function is used for B<X509v3> extensions.
=head1 NOTES
The letters B<i> and B<s> in i2s_ASN1_UTF8STRING() stand for
"internal" (that is, an internal C structure) and string respectively.
So B<i2s_ASN1_UTF8STRING>() converts from internal to string.
=head1 RETURN VALUES
B<s2i_ASN1_UTF8STRING>() return a valid
B<ASN1_UTF8STRING> structure or NULL if an error occurs.
B<i2s_ASN1_UTF8STRING>() returns the pointer to a UTF-8 string
or NULL if an error occurs.
=head1 COPYRIGHT
Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (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
L<https://www.openssl.org/source/license.html>.
=cut

@ -2,7 +2,7 @@
=head1 NAME
ASN1_generate_nconf, ASN1_generate_v3 - ASN1 generation functions
ASN1_generate_nconf, ASN1_generate_v3 - ASN1 string generation functions
=head1 SYNOPSIS
@ -16,10 +16,10 @@ ASN1_generate_nconf, ASN1_generate_v3 - ASN1 generation functions
These functions generate the ASN1 encoding of a string
in an B<ASN1_TYPE> structure.
I<str> contains the string to encode I<nconf> or I<cnf> contains
I<str> contains the string to encode. I<nconf> or I<cnf> contains
the optional configuration information where additional strings
will be read from. I<nconf> will typically come from a config
file whereas I<cnf> is obtained from an B<X509V3_CTX> structure
file whereas I<cnf> is obtained from an B<X509V3_CTX> structure,
which will typically be used by X509 v3 certificate extension
functions. I<cnf> or I<nconf> can be set to NULL if no additional
configuration will be used.

@ -0,0 +1,60 @@
=pod
=head1 NAME
X509V3_set_ctx,
X509V3_set_issuer_pkey - X.509v3 extension generation utility functions
=head1 SYNOPSIS
#include <openssl/x509v3.h>
void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
X509_REQ *req, X509_CRL *crl, int flags);
int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey);
=head1 DESCRIPTION
X509V3_set_ctx() fills in the basic fields of I<ctx> of type B<X509V3_CTX>,
providing details potentially needed by functions producing X509 v3 certificate
extensions, e.g., to look up values for filling in authority key identifiers.
Any of I<subj>, I<req>, or I<crl> may be provided, pointing to a certificate,
certification request, or certificate revocation list, respectively.
If I<subj> or I<crl> is provided, I<issuer> should point to its issuer,
for instance to help generating an authority key identifier extension.
Note that if I<subj> is provided, I<issuer> may be the same as I<subj>,
which means that I<subj> is self-issued (or even self-signed).
I<flags> may be 0 or contain B<CTX_TEST>, which means that just the syntax of
extension definitions is to be checked without actually producing an extension,
or B<X509V3_CTX_REPLACE>, which means that each X.509v3 extension added as
defined in some configuration section shall replace any already existing
extension with the same OID.
X509V3_set_issuer_pkey() explicitly sets the issuer private key of
the certificate that has been provided in I<ctx>.
This should be done for self-issued certificates (which may be self-signed
or not) to provide fallback data for the authority key identifier extension.
=head1 RETURN VALUES
X509V3_set_ctx() and X509V3_set_issuer_pkey()
return 1 on success and 0 on error.
=head1 SEE ALSO
L<X509_add_ext(3)>
=head1 HISTORY
X509V3_set_issuer_pkey() was added in OpenSSL 3.0.
=head1 COPYRIGHT
Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (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
L<https://www.openssl.org/source/license.html>.
=cut

@ -10,11 +10,13 @@ i2s_ASN1_OCTET_STRING,
s2i_ASN1_OCTET_STRING,
i2s_ASN1_ENUMERATED,
i2s_ASN1_ENUMERATED_TABLE,
i2s_ASN1_UTF8STRING,
s2i_ASN1_UTF8STRING
- convert objects from/to ASN.1/string representation
=head1 SYNOPSIS
=for openssl generic
#include <openssl/x509v3.h>
char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5);
ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
@ -29,6 +31,11 @@ i2s_ASN1_ENUMERATED_TABLE,
char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method,
const ASN1_ENUMERATED *e);
char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
ASN1_UTF8STRING *utf8);
ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str);
=head1 DESCRIPTION
These functions convert OpenSSL objects to and from their ASN.1/string
@ -36,7 +43,7 @@ representation. This function is used for B<X509v3> extensions.
=head1 NOTES
The letters B<i> and B<s> in B<i2s_ASN1_IA5STRING>() stand for
The letters B<i> and B<s> in B<i2s> and B<s2i> stand for
"internal" (that is, an internal C structure) and string respectively.
So B<i2s_ASN1_IA5STRING>() converts from internal to string.
@ -70,6 +77,16 @@ string or NULL if an error occurs.
B<s2i_ASN1_ENUMERATED>() returns the pointer to a B<ASN1_ENUMERATED>
structure or NULL if an error occurs.
B<s2i_ASN1_UTF8STRING>() return a valid
B<ASN1_UTF8STRING> structure or NULL if an error occurs.
B<i2s_ASN1_UTF8STRING>() returns the pointer to a UTF-8 string
or NULL if an error occurs.
=head1 HISTORY
i2s_ASN1_UTF8STRING() and s2i_ASN1_UTF8STRING() were made public in OpenSSL 3.0.
=head1 COPYRIGHT
Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.

@ -169,7 +169,7 @@ Examples:
=head2 Subject Key Identifier
The SKID extension specification has a value with three choices.
If the value is the word B<none>, then no SKID extension will be included.
If the value is the word B<none> then no SKID extension will be included.
If the value is the word B<hash>, or by default for the B<x509>, B<req>, and
B<ca> apps, the process specified in RFC 5280 section 4.2.1.2. (1) is followed:
The keyIdentifier is composed of the 160-bit SHA-1 hash of the value of the BIT
@ -193,14 +193,14 @@ indicated by putting a colon C<:> between the value and this option.
By default the B<x509>, B<req>, and B<ca> apps behave as if
"none" was given for self-signed certificates and "keyid, issuer" otherwise.
If B<keyid> is present, an attempt is made to copy the subject key identifier
(SKID) from the issuer certificate, which is the default behavior.
If B<keyid> is present, an attempt is made to compute the hash of the public key
corresponding to the signing key in case the certificate is self-signed,
or else to copy the subject key identifier (SKID) from the issuer certificate.
If this fails and the option B<always> is present, an error is returned.
For self-issued certs the specification for the SKID must be given before.
If B<issuer> is present and no B<keyid> has been added
or it has the option B<always> specified, then
the issuer DN and serial number are copied from the issuer certificate.
If B<issuer> is present, and in addition it has the option B<always> specified
or B<keyid> is not present,
then the issuer DN and serial number are copied from the issuer certificate.
Examples:

@ -318,3 +318,5 @@ int X509_add_cert_new(STACK_OF(X509) **sk, X509 *cert, int flags);
int X509_PUBKEY_get0_libctx(OSSL_LIB_CTX **plibctx, const char **ppropq,
const X509_PUBKEY *key);
/* Calculate default key identifier according to RFC 5280 section 4.2.1.2 (1) */
ASN1_OCTET_STRING *x509_pubkey_hash(X509_PUBKEY *pubkey);

@ -1,23 +0,0 @@
/*
* Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (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
*/
#ifndef OSSL_CRYPTO_X509V3_H
# define OSSL_CRYPTO_X509V3_H
#define EXT_UTF8STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_UTF8STRING), \
0,0,0,0, \
(X509V3_EXT_I2S)i2s_ASN1_UTF8STRING, \
(X509V3_EXT_S2I)s2i_ASN1_UTF8STRING, \
0,0,0,0, \
NULL}
char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method, ASN1_UTF8STRING *utf8);
ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str);
#endif

@ -98,6 +98,7 @@ struct v3_ext_ctx {
X509_CRL *crl;
X509V3_CONF_METHOD *db_meth;
void *db;
EVP_PKEY *issuer_pkey;
/* Maybe more here */
};
@ -380,6 +381,13 @@ struct ISSUING_DIST_POINT_st {
0,0,0,0, \
NULL}
#define EXT_UTF8STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_UTF8STRING), \
0,0,0,0, \
(X509V3_EXT_I2S)i2s_ASN1_UTF8STRING, \
(X509V3_EXT_S2I)s2i_ASN1_UTF8STRING, \
0,0,0,0, \
NULL}
# define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
/* X509_PURPOSE stuff */
@ -525,6 +533,9 @@ STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5);
ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str);
char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method, ASN1_UTF8STRING *utf8);
ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str);
STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
GENERAL_NAME *gen,
@ -645,6 +656,8 @@ void X509V3_string_free(X509V3_CTX *ctx, char *str);
void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section);
void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
X509_REQ *req, X509_CRL *crl, int flags);
/* For API backward compatibility, this is separate from X509V3_set_ctx(): */
int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey);
int X509V3_add_value(const char *name, const char *value,
STACK_OF(CONF_VALUE) **extlist);

@ -15,9 +15,9 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/;
setup("test_req");
plan tests => 39;
plan tests => 38;
require_ok(srctop_file('test','recipes','tconversion.pl'));
require_ok(srctop_file('test', 'recipes', 'tconversion.pl'));
my @certs = qw(test certs);
@ -259,7 +259,7 @@ sub generate_cert {
my $cn = $is_ca ? "CA" : "EE";
my $ca_key = srctop_file(@certs, "ca-key.pem");
my $key = $is_ca ? $ca_key : srctop_file(@certs, "ee-key.pem");
my @cmd = ("openssl", "req", "-config", "\"\"","-x509",
my @cmd = ("openssl", "req", "-config", "\"\"", "-x509",
"-key", $key, "-subj", "/CN=$cn", @_, "-out", $cert);
push(@cmd, ("-CA", $ca_cert, "-CAkey", $ca_key)) unless $ss;
ok(run(app([@cmd])), "generate $cert");
@ -286,10 +286,10 @@ sub strict_verify {
my @v3_ca = ("-addext", "basicConstraints = critical,CA:true",
"-addext", "keyUsage = keyCertSign");
my $SKID_AKID = "subjectKeyIdentifier,authorityKeyIdentifier";
my $cert = "self-signed_v1_CA_no_KIDs.pem";
generate_cert($cert);
has_SKID($ca_cert, 0);
has_AKID($ca_cert, 0);
cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID
#TODO strict_verify($cert, 1); # self-signed v1 root cert should be accepted as CA
$ca_cert = "self-signed_v3_CA_default_SKID.pem";
@ -300,15 +300,13 @@ strict_verify($ca_cert, 1);
$cert = "self-signed_v3_CA_no_SKID.pem";
generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = none");
has_SKID($cert, 0);
has_AKID($cert, 0);
cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID
#TODO strict_verify($cert, 0);
$cert = "self-signed_v3_CA_both_KIDs.pem";
generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = hash",
"-addext", "authorityKeyIdentifier = keyid");
has_SKID($cert, 1);
has_AKID($cert, 1);
cert_ext_has_n_different_lines($cert, 3, $SKID_AKID); # SKID == AKID
strict_verify($cert, 1);
$cert = "self-signed_v3_EE_wrong_keyUsage.pem";
@ -317,8 +315,7 @@ generate_cert($cert, "-addext", "keyUsage = keyCertSign");
$cert = "v3_EE_default_KIDs.pem";
generate_cert($cert, "-addext", "keyUsage = dataEncipherment");
has_SKID($cert, 1);
has_AKID($cert, 1);
cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
strict_verify($cert, 1, $ca_cert);
$cert = "v3_EE_no_AKID.pem";
@ -326,3 +323,9 @@ generate_cert($cert, "-addext", "authorityKeyIdentifier = none");
has_SKID($cert, 1);
has_AKID($cert, 0);
strict_verify($cert, 0, $ca_cert);
$cert = "self-issued_v3_EE_default_KIDs.pem";
generate_cert($cert, "-addext", "keyUsage = dataEncipherment",
"-in", srctop_file(@certs, "x509-check.csr"));
cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
strict_verify($cert, 1);

@ -111,8 +111,8 @@ sub cmp_text {
sub file_contains {
$_ = shift @_;
my $pattern = shift @_;
open(DATA,$_) or return 0;
$_= join('',<DATA>);
open(DATA, $_) or return 0;
$_= join('', <DATA>);
close(DATA);
return m/$pattern/ ? 1 : 0;
}
@ -122,11 +122,37 @@ sub cert_contains {
my $pattern = shift @_;
my $expected = shift @_;
my $name = shift @_;
my $out = "tmp.out";
my $out = "cert_contains.out";
run(app(["openssl", "x509", "-noout", "-text", "-in", $cert, "-out", $out]));
is(file_contains($out, $pattern), $expected, ($name ? "$name: " : "").
"$cert should ".($expected ? "" : "not ")."contain $pattern");
# not unlinking $out
}
sub uniq (@) {
my %seen = ();
grep { not $seen{$_}++ } @_;
}
sub file_n_different_lines {
my $filename = shift @_;
open(DATA, $filename) or return 0;
chomp(my @lines = <DATA>);
close(DATA);
return scalar(uniq @lines);
}
sub cert_ext_has_n_different_lines {
my $cert = shift @_;
my $expected = shift @_;
my $exts = shift @_;
my $name = shift @_;
my $out = "cert_n_different_exts.out";
run(app(["openssl", "x509", "-noout", "-ext", $exts,
"-in", $cert, "-out", $out]));
is(file_n_different_lines($out), $expected, ($name ? "$name: " : "").
"$cert '$exts' output should contain $expected different lines");
# not unlinking $out
}
1;

@ -5100,6 +5100,9 @@ X509_STORE_load_file_ex ? 3_0_0 EXIST::FUNCTION:
X509_STORE_load_store_ex ? 3_0_0 EXIST::FUNCTION:
X509_STORE_load_locations_ex ? 3_0_0 EXIST::FUNCTION:
X509_STORE_set_default_paths_ex ? 3_0_0 EXIST::FUNCTION:
X509V3_set_issuer_pkey ? 3_0_0 EXIST::FUNCTION:
i2s_ASN1_UTF8STRING ? 3_0_0 EXIST::FUNCTION:
s2i_ASN1_UTF8STRING ? 3_0_0 EXIST::FUNCTION:
OSSL_STORE_open_ex ? 3_0_0 EXIST::FUNCTION:
OSSL_DECODER_fetch ? 3_0_0 EXIST::FUNCTION:
OSSL_DECODER_up_ref ? 3_0_0 EXIST::FUNCTION:

@ -1294,7 +1294,6 @@ X509V3_get_value_int(3)
X509V3_parse_list(3)
X509V3_section_free(3)
X509V3_set_conf_lhash(3)
X509V3_set_ctx(3)
X509V3_set_nconf(3)
X509V3_string_free(3)
X509_ALGORS_it(3)

@ -174,3 +174,4 @@ X509V3_set_ctx_test(3)
X509V3_set_ctx_nodb(3)
EXT_BITSTRING(3)
EXT_IA5STRING(3)
EXT_UTF8STRING(3)

Loading…
Cancel
Save