=head1 NAME
-PEM_write, PEM_write_bio,
-PEM_read, PEM_read_bio, PEM_do_header, PEM_get_EVP_CIPHER_INFO
+PEM_read, PEM_read_bio, PEM_do_header, PEM_get_EVP_CIPHER_INFO, PEM_write,
+PEM_write_bio, PEM_ASN1_write, PEM_ASN1_write_bio, PEM_ASN1_write_bio_ctx
- PEM encoding routines
=head1 SYNOPSIS
#include <openssl/pem.h>
- int PEM_write(FILE *fp, const char *name, const char *header,
- const unsigned char *data, long len);
- int PEM_write_bio(BIO *bp, const char *name, const char *header,
- const unsigned char *data, long len);
-
int PEM_read(FILE *fp, char **name, char **header,
unsigned char **data, long *len);
int PEM_read_bio(BIO *bp, char **name, char **header,
int PEM_do_header(EVP_CIPHER_INFO *cinfo, unsigned char *data, long *len,
pem_password_cb *cb, void *u);
+ int PEM_write(FILE *fp, const char *name, const char *header,
+ const unsigned char *data, long len);
+ int PEM_write_bio(BIO *bp, const char *name, const char *header,
+ const unsigned char *data, long len);
+ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
+ const void *x, const EVP_CIPHER *enc,
+ const unsigned char *kstr, int klen,
+ pem_password_cb *callback, void *u);
+ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
+ const void *x, const EVP_CIPHER *enc,
+ const unsigned char *kstr, int klen,
+ pem_password_cb *callback, void *u);
+ int PEM_ASN1_write_bio_ctx(OSSL_i2d_of_void_ctx *i2d, void *vctx,
+ const char *name, BIO *bp, const void *x,
+ const EVP_CIPHER *enc, const unsigned char *kstr,
+ int klen, pem_password_cb *callback, void *u);
+
=head1 DESCRIPTION
These functions read and write PEM-encoded objects, using the PEM
=head1 RETURN VALUES
-PEM_read() and PEM_read_bio() return 1 on success and 0 on failure, the latter
-includes the case when no more PEM objects remain in the input file.
-To distinguish end of file from more serious errors the caller must peek at the
+PEM_read(), and PEM_read_bio() return 1 on success and 0 on failure, the latter
+includes the case when no more PEM objects remain in the input file. To
+distinguish end of file from more serious errors the caller must peek at the
error stack and check for B<PEM_R_NO_START_LINE>, which indicates that no more
PEM objects were found. See L<ERR_peek_last_error(3)>, L<ERR_GET_REASON(3)>.
password callback.
It will simply be treated as a byte sequence.
+PEM_write() and PEM_write_bio() return the number of encoded bytes (not
+counting the PEM header and end marker) written on success or 0 on failure.
+
+PEM_ASN1_write_bio(), and PEM_ASN1_write_bio_ctx() return 1 on success and 0 on
+failure. The latter function passes an additional application-provided context
+value to the B<i2d> function that serialises the input ASN.1 object.
+
=head1 SEE ALSO
L<ERR_peek_last_error(3)>, L<ERR_GET_LIB(3)>,
L<d2i_PKCS8PrivateKey_bio(3)>,
L<passphrase-encoding(7)>
+=head1 HISTORY
+
+The PEM_ASN1_write_bio_ctx() function was added in OpenSSL 3.5.
+
=head1 COPYRIGHT
Copyright 1998-2020 The OpenSSL Project Authors. All Rights Reserved.
# define OPENSSL_NO_KEYPARAMS
#endif
-struct key2any_ctx_st {
+typedef struct key2any_ctx_st {
PROV_CTX *provctx;
/* Set to 0 if parameters should not be saved (dsa only) */
EVP_CIPHER *cipher;
struct ossl_passphrase_data_st pwdata;
-};
+} KEY2ANY_CTX;
typedef int check_key_type_fn(const void *key, int nid);
typedef int key_to_paramstring_fn(const void *key, int nid, int save,
void **str, int *strtype);
typedef int key_to_der_fn(BIO *out, const void *key,
int key_nid, const char *pemname,
- key_to_paramstring_fn *p2s, i2d_of_void *k2d,
- struct key2any_ctx_st *ctx);
+ key_to_paramstring_fn *p2s,
+ OSSL_i2d_of_void_ctx *k2d, KEY2ANY_CTX *ctx);
typedef int write_bio_of_void_fn(BIO *bp, const void *x);
static PKCS8_PRIV_KEY_INFO *key_to_p8info(const void *key, int key_nid,
void *params, int params_type,
- i2d_of_void *k2d)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
/* der, derlen store the key DER output and its length */
unsigned char *der = NULL;
PKCS8_PRIV_KEY_INFO *p8info = NULL;
if ((p8info = PKCS8_PRIV_KEY_INFO_new()) == NULL
- || (derlen = k2d(key, &der)) <= 0
+ || (derlen = k2d(key, &der, (void *)ctx)) <= 0
|| !PKCS8_pkey_set0(p8info, OBJ_nid2obj(key_nid), 0,
params_type, params, der, derlen)) {
ERR_raise(ERR_LIB_PROV, ERR_R_ASN1_LIB);
}
static X509_SIG *p8info_to_encp8(PKCS8_PRIV_KEY_INFO *p8info,
- struct key2any_ctx_st *ctx)
+ KEY2ANY_CTX *ctx)
{
X509_SIG *p8 = NULL;
char kstr[PEM_BUFSIZE];
static X509_SIG *key_to_encp8(const void *key, int key_nid,
void *params, int params_type,
- i2d_of_void *k2d, struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
PKCS8_PRIV_KEY_INFO *p8info =
- key_to_p8info(key, key_nid, params, params_type, k2d);
+ key_to_p8info(key, key_nid, params, params_type, k2d, ctx);
X509_SIG *p8 = NULL;
if (p8info == NULL) {
static X509_PUBKEY *key_to_pubkey(const void *key, int key_nid,
void *params, int params_type,
- i2d_of_void k2d)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
/* der, derlen store the key DER output and its length */
unsigned char *der = NULL;
if ((xpk = X509_PUBKEY_new()) == NULL
- || (derlen = k2d(key, &der)) <= 0
+ || (derlen = k2d(key, &der, (void *)ctx)) <= 0
|| !X509_PUBKEY_set0_param(xpk, OBJ_nid2obj(key_nid),
params_type, params, der, derlen)) {
ERR_raise(ERR_LIB_PROV, ERR_R_X509_LIB);
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
int ret = 0;
void *str = NULL;
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
int ret = 0;
void *str = NULL;
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
int ret = 0;
void *str = NULL;
&str, &strtype))
return 0;
- p8info = key_to_p8info(key, key_nid, str, strtype, k2d);
+ p8info = key_to_p8info(key, key_nid, str, strtype, k2d, ctx);
if (p8info != NULL)
ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info);
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
int ret = 0;
void *str = NULL;
&str, &strtype))
return 0;
- p8info = key_to_p8info(key, key_nid, str, strtype, k2d);
+ p8info = key_to_p8info(key, key_nid, str, strtype, k2d, ctx);
if (p8info != NULL)
ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info);
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
int ret = 0;
void *str = NULL;
&str, &strtype))
return 0;
- xpk = key_to_pubkey(key, key_nid, str, strtype, k2d);
+ xpk = key_to_pubkey(key, key_nid, str, strtype, k2d, ctx);
if (xpk != NULL)
ret = i2d_X509_PUBKEY_bio(out, xpk);
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
int ret = 0;
void *str = NULL;
&str, &strtype))
return 0;
- xpk = key_to_pubkey(key, key_nid, str, strtype, k2d);
+ xpk = key_to_pubkey(key, key_nid, str, strtype, k2d, ctx);
if (xpk != NULL)
ret = PEM_write_bio_X509_PUBKEY(out, xpk);
int key_nid,
ossl_unused const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
unsigned char *der = NULL;
int derlen;
int ret;
- if ((derlen = k2d(key, &der)) <= 0) {
+ if ((derlen = k2d(key, &der, (void *)ctx)) <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_R_PROV_LIB);
return 0;
}
static int key_to_type_specific_pem_bio_cb(BIO *out, const void *key,
int key_nid, const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx,
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx,
pem_password_cb *cb, void *cbarg)
{
- return
- PEM_ASN1_write_bio(k2d, pemname, out, key, ctx->cipher,
- NULL, 0, cb, cbarg) > 0;
+ return PEM_ASN1_write_bio_ctx(k2d, (void *)ctx, pemname, out, key,
+ ctx->cipher, NULL, 0, cb, cbarg) > 0;
}
static int key_to_type_specific_pem_priv_bio(BIO *out, const void *key,
int key_nid, const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
p2s, k2d, ctx,
static int key_to_type_specific_pem_pub_bio(BIO *out, const void *key,
int key_nid, const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
p2s, k2d, ctx, NULL, NULL);
static int key_to_type_specific_pem_param_bio(BIO *out, const void *key,
int key_nid, const char *pemname,
key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+ OSSL_i2d_of_void_ctx *k2d,
+ KEY2ANY_CTX *ctx)
{
return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
p2s, k2d, ctx, NULL, NULL);
/* ---------------------------------------------------------------------- */
+#define k2d_NOCTX(n, f) \
+ static int \
+ n##_k2d(const void *key, unsigned char **pder, \
+ ossl_unused void *ctx) \
+ { \
+ return f(key, pder); \
+ }
+
+/* ---------------------------------------------------------------------- */
+
#ifndef OPENSSL_NO_DH
static int prepare_dh_params(const void *dh, int nid, int save,
void **pstr, int *pstrtype)
return 1;
}
-static int dh_spki_pub_to_der(const void *dh, unsigned char **pder)
+static int dh_spki_pub_to_der(const void *dh, unsigned char **pder,
+ ossl_unused void *ctx)
{
const BIGNUM *bn = NULL;
ASN1_INTEGER *pub_key = NULL;
return ret;
}
-static int dh_pki_priv_to_der(const void *dh, unsigned char **pder)
+static int dh_pki_priv_to_der(const void *dh, unsigned char **pder,
+ ossl_unused void *ctx)
{
const BIGNUM *bn = NULL;
ASN1_INTEGER *priv_key = NULL;
# define dh_epki_priv_to_der dh_pki_priv_to_der
-static int dh_type_specific_params_to_der(const void *dh, unsigned char **pder)
+static int
+dh_type_specific_params_to_der(const void *dh, unsigned char **pder,
+ ossl_unused void *ctx)
{
if (DH_test_flags(dh, DH_FLAG_TYPE_DHX))
return i2d_DHxparams(dh, pder);
return 1;
}
-static int dsa_spki_pub_to_der(const void *dsa, unsigned char **pder)
+static int dsa_spki_pub_to_der(const void *dsa, unsigned char **pder,
+ ossl_unused void *ctx)
{
const BIGNUM *bn = NULL;
ASN1_INTEGER *pub_key = NULL;
return ret;
}
-static int dsa_pki_priv_to_der(const void *dsa, unsigned char **pder)
+static int dsa_pki_priv_to_der(const void *dsa, unsigned char **pder,
+ ossl_unused void *ctx)
{
const BIGNUM *bn = NULL;
ASN1_INTEGER *priv_key = NULL;
return ret;
}
+k2d_NOCTX(dsa_prv, i2d_DSAPrivateKey)
+k2d_NOCTX(dsa_pub, i2d_DSAPublicKey)
+k2d_NOCTX(dsa_param, i2d_DSAparams)
+
# define dsa_epki_priv_to_der dsa_pki_priv_to_der
-# define dsa_type_specific_priv_to_der (i2d_of_void *)i2d_DSAPrivateKey
-# define dsa_type_specific_pub_to_der (i2d_of_void *)i2d_DSAPublicKey
-# define dsa_type_specific_params_to_der (i2d_of_void *)i2d_DSAparams
+# define dsa_type_specific_priv_to_der dsa_prv_k2d
+# define dsa_type_specific_pub_to_der dsa_pub_k2d
+# define dsa_type_specific_params_to_der dsa_param_k2d
# define dsa_check_key_type NULL
# define dsa_evp_type EVP_PKEY_DSA
}
}
-static int ec_spki_pub_to_der(const void *eckey, unsigned char **pder)
+static int ec_spki_pub_to_der(const void *eckey, unsigned char **pder,
+ ossl_unused void *ctx)
{
if (EC_KEY_get0_public_key(eckey) == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
return i2o_ECPublicKey(eckey, pder);
}
-static int ec_pki_priv_to_der(const void *veckey, unsigned char **pder)
+static int ec_pki_priv_to_der(const void *veckey, unsigned char **pder,
+ ossl_unused void *ctx)
{
EC_KEY *eckey = (EC_KEY *)veckey;
unsigned int old_flags;
return ret; /* return the length of the der encoded data */
}
+k2d_NOCTX(ec_param, i2d_ECParameters)
+k2d_NOCTX(ec_prv, i2d_ECPrivateKey)
+
# define ec_epki_priv_to_der ec_pki_priv_to_der
-# define ec_type_specific_params_to_der (i2d_of_void *)i2d_ECParameters
+# define ec_type_specific_params_to_der ec_param_k2d
/* No ec_type_specific_pub_to_der, there simply is no such thing */
-# define ec_type_specific_priv_to_der (i2d_of_void *)i2d_ECPrivateKey
+# define ec_type_specific_priv_to_der ec_prv_k2d
# define ec_check_key_type NULL
# define ec_evp_type EVP_PKEY_EC
#ifndef OPENSSL_NO_ECX
# define prepare_ecx_params NULL
-static int ecx_spki_pub_to_der(const void *vecxkey, unsigned char **pder)
+static int ecx_spki_pub_to_der(const void *vecxkey, unsigned char **pder,
+ ossl_unused void *ctx)
{
const ECX_KEY *ecxkey = vecxkey;
unsigned char *keyblob;
return ecxkey->keylen;
}
-static int ecx_pki_priv_to_der(const void *vecxkey, unsigned char **pder)
+static int ecx_pki_priv_to_der(const void *vecxkey, unsigned char **pder,
+ ossl_unused void *ctx)
{
const ECX_KEY *ecxkey = vecxkey;
ASN1_OCTET_STRING oct;
return 0;
}
+k2d_NOCTX(rsa_prv, i2d_RSAPrivateKey)
+k2d_NOCTX(rsa_pub, i2d_RSAPublicKey)
+
/*
* RSA is extremely simple, as PKCS#1 is used for the PKCS#8 |privateKey|
* field as well as the SubjectPublicKeyInfo |subjectPublicKey| field.
#define rsa_pki_priv_to_der rsa_type_specific_priv_to_der
#define rsa_epki_priv_to_der rsa_type_specific_priv_to_der
#define rsa_spki_pub_to_der rsa_type_specific_pub_to_der
-#define rsa_type_specific_priv_to_der (i2d_of_void *)i2d_RSAPrivateKey
-#define rsa_type_specific_pub_to_der (i2d_of_void *)i2d_RSAPublicKey
+#define rsa_type_specific_priv_to_der rsa_prv_k2d
+#define rsa_type_specific_pub_to_der rsa_pub_k2d
#define rsa_type_specific_params_to_der NULL
static int rsa_check_key_type(const void *rsa, int expected_type)
static void *key2any_newctx(void *provctx)
{
- struct key2any_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
+ KEY2ANY_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL) {
ctx->provctx = provctx;
static void key2any_freectx(void *vctx)
{
- struct key2any_ctx_st *ctx = vctx;
+ KEY2ANY_CTX *ctx = vctx;
ossl_pw_clear_passphrase_data(&ctx->pwdata);
EVP_CIPHER_free(ctx->cipher);
static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
- struct key2any_ctx_st *ctx = vctx;
+ KEY2ANY_CTX *ctx = vctx;
OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx);
const OSSL_PARAM *cipherp =
OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_CIPHER);
return 0;
}
-static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout,
+static int key2any_encode(KEY2ANY_CTX *ctx, OSSL_CORE_BIO *cout,
const void *key, int type, const char *pemname,
check_key_type_fn *checker,
key_to_der_fn *writer,
OSSL_PASSPHRASE_CALLBACK *pwcb, void *pwcbarg,
key_to_paramstring_fn *key2paramstring,
- i2d_of_void *key2der)
+ OSSL_i2d_of_void_ctx *key2der)
{
int ret = 0;
impl##_to_##kind##_##output##_import_object(void *vctx, int selection, \
const OSSL_PARAM params[]) \
{ \
- struct key2any_ctx_st *ctx = vctx; \
+ KEY2ANY_CTX *ctx = vctx; \
\
return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \
ctx->provctx, selection, params); \