summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/cmp.c69
-rw-r--r--crypto/cmp/cmp_ctx.c30
-rw-r--r--crypto/cmp/cmp_local.h2
-rw-r--r--doc/man1/openssl-cmp.pod.in5
-rw-r--r--doc/man3/OSSL_CMP_CTX_new.pod9
-rw-r--r--include/openssl/cmp.h1
-rw-r--r--test/cmp_ctx_test.c4
-rw-r--r--util/libcrypto.num1
8 files changed, 84 insertions, 37 deletions
diff --git a/apps/cmp.c b/apps/cmp.c
index 4d6acdd499..1af27f7881 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -129,6 +129,7 @@ static char *opt_out_trusted = NULL;
static int opt_implicit_confirm = 0;
static int opt_disable_confirm = 0;
static char *opt_certout = NULL;
+static char *opt_chainout = NULL;
/* certificate enrollment and revocation */
static char *opt_oldcert = NULL;
@@ -205,7 +206,7 @@ typedef enum OPTION_choice {
OPT_POLICIES, OPT_POLICY_OIDS, OPT_POLICY_OIDS_CRITICAL,
OPT_POPO, OPT_CSR,
OPT_OUT_TRUSTED, OPT_IMPLICIT_CONFIRM, OPT_DISABLE_CONFIRM,
- OPT_CERTOUT,
+ OPT_CERTOUT, OPT_CHAINOUT,
OPT_OLDCERT, OPT_REVREASON,
@@ -314,6 +315,8 @@ const OPTIONS cmp_options[] = {
"confirmation. WARNING: This leads to behavior violating RFC 4210"},
{"certout", OPT_CERTOUT, 's',
"File to save newly enrolled certificate"},
+ {"chainout", OPT_CHAINOUT, 's',
+ "File to save the chain of newly enrolled certificate"},
OPT_SECTION("Certificate enrollment and revocation"),
@@ -521,7 +524,7 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
{(char **)&opt_popo}, {&opt_csr},
{&opt_out_trusted},
{(char **)&opt_implicit_confirm}, {(char **)&opt_disable_confirm},
- {&opt_certout},
+ {&opt_certout}, {&opt_chainout},
{&opt_oldcert}, {(char **)&opt_revreason},
@@ -2066,18 +2069,21 @@ static int write_cert(BIO *bio, X509 *cert)
}
/*
- * writes out a stack of certs to the given file.
+ * If destFile != NULL writes out a stack of certs to the given file.
+ * In any case frees the certs.
* Depending on options use either PEM or DER format,
* where DER does not make much sense for writing more than one cert!
- * Returns number of written certificates on success, 0 on error.
+ * Returns number of written certificates on success, -1 on error.
*/
-static int save_certs(OSSL_CMP_CTX *ctx,
- STACK_OF(X509) *certs, char *destFile, char *desc)
+static int save_free_certs(OSSL_CMP_CTX *ctx,
+ STACK_OF(X509) *certs, char *destFile, char *desc)
{
BIO *bio = NULL;
int i;
int n = sk_X509_num(certs);
+ if (destFile == NULL)
+ goto end;
CMP_info3("received %d %s certificate(s), saving to file '%s'",
n, desc, destFile);
if (n > 1 && opt_certform != FORMAT_PEM)
@@ -2087,19 +2093,20 @@ static int save_certs(OSSL_CMP_CTX *ctx,
|| !BIO_write_filename(bio, (char *)destFile)) {
CMP_err1("could not open file '%s' for writing", destFile);
n = -1;
- goto err;
+ goto end;
}
for (i = 0; i < n; i++) {
if (!write_cert(bio, sk_X509_value(certs, i))) {
CMP_err1("cannot write certificate to file '%s'", destFile);
n = -1;
- goto err;
+ goto end;
}
}
- err:
+ end:
BIO_free(bio);
+ sk_X509_pop_free(certs, X509_free);
return n;
}
@@ -2511,6 +2518,9 @@ static int get_opts(int argc, char **argv)
case OPT_CERTOUT:
opt_certout = opt_str("certout");
break;
+ case OPT_CHAINOUT:
+ opt_chainout = opt_str("chainout");
+ break;
case OPT_OLDCERT:
opt_oldcert = opt_str("oldcert");
break;
@@ -2935,39 +2945,26 @@ int cmp_main(int argc, char **argv)
OPENSSL_free(buf);
}
- if (opt_cacertsout != NULL) {
- STACK_OF(X509) *certs = OSSL_CMP_CTX_get1_caPubs(cmp_ctx);
-
- if (sk_X509_num(certs) > 0
- && save_certs(cmp_ctx, certs, opt_cacertsout, "CA") < 0) {
- sk_X509_pop_free(certs, X509_free);
- goto err;
- }
- sk_X509_pop_free(certs, X509_free);
- }
-
- if (opt_extracertsout != NULL) {
- STACK_OF(X509) *certs = OSSL_CMP_CTX_get1_extraCertsIn(cmp_ctx);
- if (sk_X509_num(certs) > 0
- && save_certs(cmp_ctx, certs, opt_extracertsout,
- "extra") < 0) {
- sk_X509_pop_free(certs, X509_free);
- goto err;
- }
- sk_X509_pop_free(certs, X509_free);
- }
-
- if (opt_certout != NULL && newcert != NULL) {
+ if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_caPubs(cmp_ctx),
+ opt_cacertsout, "CA") < 0)
+ goto err;
+ if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_extraCertsIn(cmp_ctx),
+ opt_extracertsout, "extra") < 0)
+ goto err;
+ if (newcert != NULL) {
STACK_OF(X509) *certs = sk_X509_new_null();
- if (certs == NULL || !sk_X509_push(certs, newcert)
- || save_certs(cmp_ctx, certs, opt_certout,
- "enrolled") < 0) {
+ if (!X509_add_cert(certs, newcert, X509_ADD_FLAG_UP_REF)) {
sk_X509_free(certs);
goto err;
}
- sk_X509_free(certs);
+ if (save_free_certs(cmp_ctx, certs, opt_certout, "enrolled") < 0)
+ goto err;
}
+ if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_newChain(cmp_ctx),
+ opt_chainout, "chain") < 0)
+ goto err;
+
if (!OSSL_CMP_CTX_reinit(cmp_ctx))
goto err;
}
diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c
index 57878a8f8d..50c5d0e061 100644
--- a/crypto/cmp/cmp_ctx.c
+++ b/crypto/cmp/cmp_ctx.c
@@ -162,6 +162,7 @@ int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx)
return ossl_cmp_ctx_set0_statusString(ctx, NULL)
&& ossl_cmp_ctx_set0_newCert(ctx, NULL)
+ && ossl_cmp_ctx_set1_newChain(ctx, NULL)
&& ossl_cmp_ctx_set1_caPubs(ctx, NULL)
&& ossl_cmp_ctx_set1_extraCertsIn(ctx, NULL)
&& ossl_cmp_ctx_set0_validatedSrvCert(ctx, NULL)
@@ -216,6 +217,7 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx)
sk_ASN1_UTF8STRING_pop_free(ctx->statusString, ASN1_UTF8STRING_free);
X509_free(ctx->newCert);
+ sk_X509_pop_free(ctx->newChain, X509_free);
sk_X509_pop_free(ctx->caPubs, X509_free);
sk_X509_pop_free(ctx->extraCertsIn, X509_free);
@@ -459,6 +461,34 @@ int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx, const unsigned char *sec,
return 1;
}
+/* Returns the cert chain computed by OSSL_CMP_certConf_cb(), NULL on error */
+STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx)
+{
+ if (ctx == NULL) {
+ CMPerr(0, CMP_R_NULL_ARGUMENT);
+ return NULL;
+ }
+ if (ctx->newChain == NULL)
+ return sk_X509_new_null();
+ return X509_chain_up_ref(ctx->newChain);
+}
+
+/*
+ * Copies any given stack of inbound X509 certificates to newChain
+ * of the OSSL_CMP_CTX structure so that they may be retrieved later.
+ */
+int ossl_cmp_ctx_set1_newChain(OSSL_CMP_CTX *ctx, STACK_OF(X509) *newChain)
+{
+ if (!ossl_assert(ctx != NULL))
+ return 0;
+
+ sk_X509_pop_free(ctx->newChain, X509_free);
+ ctx->newChain= NULL;
+ if (newChain == NULL)
+ return 1;
+ return (ctx->newChain = X509_chain_up_ref(newChain)) != NULL;
+}
+
/*
* Returns the stack of certificates received in a response message.
* The stack is duplicated so the caller must handle freeing it!
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index 41c10b22c1..a6e55cfd1b 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -120,6 +120,7 @@ struct ossl_cmp_ctx_st {
/* TODO: this should be a stack since there could be more than one */
X509 *newCert; /* newly enrolled cert received from the CA */
/* TODO: this should be a stack since there could be more than one */
+ STACK_OF(X509) *newChain; /* chain of newly enrolled cert received */
STACK_OF(X509) *caPubs; /* CA certs received from server (in IP message) */
STACK_OF(X509) *extraCertsIn; /* extraCerts received from server */
@@ -780,6 +781,7 @@ int ossl_cmp_ctx_set0_statusString(OSSL_CMP_CTX *ctx,
OSSL_CMP_PKIFREETEXT *text);
int ossl_cmp_ctx_set_failInfoCode(OSSL_CMP_CTX *ctx, int fail_info);
int ossl_cmp_ctx_set0_newCert(OSSL_CMP_CTX *ctx, X509 *cert);
+int ossl_cmp_ctx_set1_newChain(OSSL_CMP_CTX *ctx, STACK_OF(X509) *newChain);
int ossl_cmp_ctx_set1_caPubs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *caPubs);
int ossl_cmp_ctx_set1_extraCertsIn(OSSL_CMP_CTX *ctx,
STACK_OF(X509) *extraCertsIn);
diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in
index 760e21ccbe..d91bd31684 100644
--- a/doc/man1/openssl-cmp.pod.in
+++ b/doc/man1/openssl-cmp.pod.in
@@ -63,6 +63,7 @@ B<openssl> B<cmp>
[B<-implicit_confirm>]
[B<-disable_confirm>]
[B<-certout> I<filename>]
+[B<-chainout> I<filename>]
[B<-oldcert> I<filename>]
[B<-revreason> I<number>]
@@ -378,6 +379,10 @@ B<WARNING:> This leads to behavior violating RFC 4210.
The file where the newly enrolled certificate should be saved.
+=item B<-chainout> I<filename>
+
+The file where the chain of the newly enrolled certificate should be saved.
+
=back
diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod
index 62e1a562c9..fda5150434 100644
--- a/doc/man3/OSSL_CMP_CTX_new.pod
+++ b/doc/man3/OSSL_CMP_CTX_new.pod
@@ -54,6 +54,7 @@ OSSL_CMP_CTX_get_status,
OSSL_CMP_CTX_get0_statusString,
OSSL_CMP_CTX_get_failInfoCode,
OSSL_CMP_CTX_get0_newCert,
+OSSL_CMP_CTX_get1_newChain,
OSSL_CMP_CTX_get1_caPubs,
OSSL_CMP_CTX_get1_extraCertsIn,
OSSL_CMP_CTX_set1_transactionID,
@@ -144,6 +145,7 @@ OSSL_CMP_CTX_set1_senderNonce
int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx);
X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx);
+ STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx);
@@ -170,7 +172,7 @@ OSSL_CMP_CTX_free() deallocates an OSSL_CMP_CTX structure.
OSSL_CMP_CTX_reinit() prepares the given B<ctx> for a further transaction by
clearing the internal CMP transaction (aka session) status, PKIStatusInfo,
-and any previous results (newCert, caPubs, and extraCertsIn)
+and any previous results (newCert, newChain, caPubs, and extraCertsIn)
from the last executed transaction.
All other field values (i.e., CMP options) are retained for potential re-use.
@@ -579,6 +581,10 @@ OSSL_CMP_CTX_FAILINFO_badAlg. Returns -1 if the failInfoCode field is unset.
OSSL_CMP_CTX_get0_newCert() returns the pointer to the newly obtained
certificate in case it is available, else NULL.
+OSSL_CMP_CTX_get1_newChain() returns a pointer to a duplicate of the stack of
+X.509 certificates computed by OSSL_CMP_certConf_cb() (if this function has
+been called) on the last received certificate response message IP/CP/KUP.
+
OSSL_CMP_CTX_get1_caPubs() returns a pointer to a duplicate of the stack of
X.509 certificates received in the caPubs field of last received certificate
response message IP/CP/KUP.
@@ -611,6 +617,7 @@ OSSL_CMP_CTX_get0_newPkey(),
OSSL_CMP_CTX_get_certConf_cb_arg(),
OSSL_CMP_CTX_get0_statusString(),
OSSL_CMP_CTX_get0_newCert(),
+OSSL_CMP_CTX_get0_newChain(),
OSSL_CMP_CTX_get1_caPubs(), and
OSSL_CMP_CTX_get1_extraCertsIn()
return the intended pointer value as described above or NULL on error.
diff --git a/include/openssl/cmp.h b/include/openssl/cmp.h
index cf79a4c71f..d12d48ba4f 100644
--- a/include/openssl/cmp.h
+++ b/include/openssl/cmp.h
@@ -331,6 +331,7 @@ OSSL_CMP_PKIFREETEXT *OSSL_CMP_CTX_get0_statusString(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx);
# define OSSL_CMP_PKISI_BUFLEN 1024
X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx);
+STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
diff --git a/test/cmp_ctx_test.c b/test/cmp_ctx_test.c
index 184e5bf498..9b2a53df5f 100644
--- a/test/cmp_ctx_test.c
+++ b/test/cmp_ctx_test.c
@@ -76,6 +76,7 @@ static int execute_CTX_reinit_test(OSSL_CMP_CTX_TEST_FIXTURE *fixture)
if (!ossl_cmp_ctx_set0_statusString(ctx, sk_ASN1_UTF8STRING_new_null())
|| !ossl_cmp_ctx_set0_newCert(ctx, X509_new())
|| !TEST_ptr(certs = sk_X509_new_1())
+ || !ossl_cmp_ctx_set1_newChain(ctx, certs)
|| !ossl_cmp_ctx_set1_caPubs(ctx, certs)
|| !ossl_cmp_ctx_set1_extraCertsIn(ctx, certs)
|| !ossl_cmp_ctx_set0_validatedSrvCert(ctx, X509_new())
@@ -93,6 +94,7 @@ static int execute_CTX_reinit_test(OSSL_CMP_CTX_TEST_FIXTURE *fixture)
&& ctx->failInfoCode == -1
&& ctx->statusString == NULL
&& ctx->newCert == NULL
+ && ctx->newChain == NULL
&& ctx->caPubs == NULL
&& ctx->extraCertsIn == NULL
&& ctx->validatedSrvCert == NULL
@@ -780,6 +782,7 @@ DEFINE_SET_GET_INT_TEST(ossl_cmp, ctx, status)
DEFINE_SET_GET_SK_TEST(ossl_cmp, ctx, 0, 0, statusString, ASN1_UTF8STRING)
DEFINE_SET_GET_INT_TEST(ossl_cmp, ctx, failInfoCode)
DEFINE_SET_GET_TEST(ossl_cmp, ctx, 0, 0, 0, newCert, X509)
+DEFINE_SET_GET_SK_X509_TEST(ossl_cmp, ctx, 1, 1, newChain)
DEFINE_SET_GET_SK_X509_TEST(ossl_cmp, ctx, 1, 1, caPubs)
DEFINE_SET_GET_SK_X509_TEST(ossl_cmp, ctx, 1, 1, extraCertsIn)
@@ -869,6 +872,7 @@ int setup_tests(void)
ADD_TEST(test_CTX_set0_get0_statusString);
ADD_TEST(test_CTX_set_get_failInfoCode);
ADD_TEST(test_CTX_set0_get0_newCert);
+ ADD_TEST(test_CTX_set1_get1_newChain);
ADD_TEST(test_CTX_set1_get1_caPubs);
ADD_TEST(test_CTX_set1_get1_extraCertsIn);
/* exported for testing and debugging purposes: */
diff --git a/util/libcrypto.num b/util/libcrypto.num
index d5e7ab423e..cfe1cb8bc6 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4797,6 +4797,7 @@ OSSL_CMP_CTX_get_status ? 3_0_0 EXIST::FUNCTION:CMP
OSSL_CMP_CTX_get0_statusString ? 3_0_0 EXIST::FUNCTION:CMP
OSSL_CMP_CTX_get_failInfoCode ? 3_0_0 EXIST::FUNCTION:CMP
OSSL_CMP_CTX_get0_newCert ? 3_0_0 EXIST::FUNCTION:CMP
+OSSL_CMP_CTX_get1_newChain ? 3_0_0 EXIST::FUNCTION:CMP
OSSL_CMP_CTX_get1_caPubs ? 3_0_0 EXIST::FUNCTION:CMP
OSSL_CMP_CTX_get1_extraCertsIn ? 3_0_0 EXIST::FUNCTION:CMP
OSSL_CMP_CTX_set1_transactionID ? 3_0_0 EXIST::FUNCTION:CMP