-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add support for PEM Parameters without ASN1 hooks #1831
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,7 @@ | |
#include <openssl/pkcs8.h> | ||
#include <openssl/rand.h> | ||
#include <openssl/x509.h> | ||
#include "../fipsmodule/evp/internal.h" | ||
|
||
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, | ||
void *u) { | ||
|
@@ -156,6 +157,88 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, | |
return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (char *)kstr, klen, cb, u); | ||
} | ||
|
||
EVP_PKEY *PEM_read_bio_Parameters(BIO *bio, EVP_PKEY **pkey) { | ||
char *nm = NULL; | ||
unsigned char *data = NULL; | ||
long len; | ||
if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_PARAMETERS, bio, 0, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NP: We have zero documentation for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added documentation |
||
NULL)) { | ||
return NULL; | ||
} | ||
const unsigned char *data_const = data; | ||
|
||
// Implementing the ASN1 logic here allows us to decouple the pem logic for | ||
// |EVP_PKEY|. These correspond to the historical |param_decode| | ||
// |EVP_PKEY_ASN1_METHOD| hooks in OpenSSL. | ||
EVP_PKEY *ret = EVP_PKEY_new(); | ||
samuel40791765 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (strcmp(nm, PEM_STRING_ECPARAMETERS) == 0) { | ||
EC_KEY *ec_key = d2i_ECParameters(NULL, &data_const, len); | ||
if (ec_key == NULL || !EVP_PKEY_assign_EC_KEY(ret, ec_key)) { | ||
OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); | ||
EC_KEY_free(ec_key); | ||
goto err; | ||
} | ||
} else if (strcmp(nm, PEM_STRING_DSAPARAMS) == 0) { | ||
DSA *dsa = d2i_DSAparams(NULL, &data_const, len); | ||
if (dsa == NULL || !EVP_PKEY_assign_DSA(ret, dsa)) { | ||
OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB); | ||
DSA_free(dsa); | ||
goto err; | ||
} | ||
} else if (strcmp(nm, PEM_STRING_DHPARAMS) == 0) { | ||
DH *dh = d2i_DHparams(NULL, &data_const, len); | ||
if (dh == NULL || !EVP_PKEY_assign_DH(ret, dh)) { | ||
OPENSSL_PUT_ERROR(EVP, ERR_R_DH_LIB); | ||
DH_free(dh); | ||
goto err; | ||
} | ||
} else { | ||
goto err; | ||
} | ||
|
||
if (pkey != NULL) { | ||
EVP_PKEY_free(*pkey); | ||
*pkey = ret; | ||
} | ||
|
||
OPENSSL_free(nm); | ||
OPENSSL_free(data); | ||
return ret; | ||
|
||
err: | ||
EVP_PKEY_free(ret); | ||
OPENSSL_free(nm); | ||
OPENSSL_free(data); | ||
return NULL; | ||
} | ||
|
||
int PEM_write_bio_Parameters(BIO *bio, EVP_PKEY *pkey) { | ||
if (bio == NULL || pkey == NULL || pkey->ameth == NULL) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the check for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, this is a remnant of the original way OpenSSL had implemented these. I tried checking for |
||
return 0; | ||
} | ||
|
||
// Implementing the ASN1 logic here allows us to decouple the pem logic for | ||
// |EVP_PKEY|. These correspond to the historical |param_encode| | ||
// |EVP_PKEY_ASN1_METHOD| hooks in OpenSSL. | ||
char pem_str[80]; | ||
switch (pkey->type) { | ||
case EVP_PKEY_EC: | ||
BIO_snprintf(pem_str, 80, PEM_STRING_ECPARAMETERS); | ||
return PEM_ASN1_write_bio((i2d_of_void *)i2d_ECParameters, pem_str, bio, | ||
pkey->pkey.ec, NULL, NULL, 0, 0, NULL); | ||
case EVP_PKEY_DSA: | ||
BIO_snprintf(pem_str, 80, PEM_STRING_DSAPARAMS); | ||
return PEM_ASN1_write_bio((i2d_of_void *)i2d_DSAparams, pem_str, bio, | ||
pkey->pkey.dsa, NULL, NULL, 0, 0, NULL); | ||
case EVP_PKEY_DH: | ||
BIO_snprintf(pem_str, 80, PEM_STRING_DHPARAMS); | ||
return PEM_ASN1_write_bio((i2d_of_void *)i2d_DHparams, pem_str, bio, | ||
pkey->pkey.dh, NULL, NULL, 0, 0, NULL); | ||
default: | ||
return 0; | ||
} | ||
} | ||
|
||
EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, | ||
void *u) { | ||
BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,6 +107,7 @@ extern "C" { | |
#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" | ||
#define PEM_STRING_ECPARAMETERS "EC PARAMETERS" | ||
#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" | ||
#define PEM_STRING_PARAMETERS "PARAMETERS" | ||
#define PEM_STRING_CMS "CMS" | ||
|
||
// enc_type is one off | ||
|
@@ -473,6 +474,19 @@ OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey(FILE *fp, const EVP_PKEY *x, | |
int klen, pem_password_cb *cd, | ||
void *u); | ||
|
||
// PEM_read_bio_Parameters is a generic PEM deserialization function that | ||
// parses the public "parameters" in |bio| and returns a corresponding | ||
// |EVP_PKEY|. If |*pkey| is non-null, the original |*pkey| is freed and the | ||
// returned |EVP_PKEY| is also written to |*pkey|. This is only supported with | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it's implied from this statement, but it would be good to explicitly say that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added clarification |
||
// |EVP_PKEY_EC|, |EVP_PKEY_DH|, and |EVP_PKEY_DSA|. | ||
OPENSSL_EXPORT EVP_PKEY *PEM_read_bio_Parameters(BIO *bio, EVP_PKEY **pkey); | ||
|
||
// PEM_write_bio_Parameters is a generic PEM serialization function that parses | ||
// the public "parameters" of |pkey| to |bio|. It returns 1 on success or 0 on | ||
// failure. This is only supported with |EVP_PKEY_EC|, |EVP_PKEY_DH|, and | ||
// |EVP_PKEY_DSA|. | ||
OPENSSL_EXPORT int PEM_write_bio_Parameters(BIO *bio, EVP_PKEY *pkey); | ||
|
||
// PEM_read_bio_ECPKParameters deserializes the PEM file written in |bio| | ||
// according to |ECPKParameters| in RFC 3279. It returns the |EC_GROUP| | ||
// corresponding to deserialized output and also writes it to |out_group|. Only | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NP: The remainder of this function does not have any test coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if the remainder are related to PEM functions we're implementing for this PR. This function is a generic function for parsing the first line of PEM files and the rest below apply to other supported formats.