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;
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,
"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"),
{(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},
}
/*
- * 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)
|| !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;
}
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;
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;
}
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)
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);
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!
/* 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 */
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);
[B<-implicit_confirm>]
[B<-disable_confirm>]
[B<-certout> I<filename>]
+[B<-chainout> I<filename>]
[B<-oldcert> I<filename>]
[B<-revreason> I<number>]
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
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,
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);
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.
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.
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.
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,
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())
&& ctx->failInfoCode == -1
&& ctx->statusString == NULL
&& ctx->newCert == NULL
+ && ctx->newChain == NULL
&& ctx->caPubs == NULL
&& ctx->extraCertsIn == NULL
&& ctx->validatedSrvCert == NULL
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)
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: */
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