Clarify thread-safety of key objects. This often causes confusion since, for various silly reasons (intrinsic ref-counting, FOO_METHOD, and RSA's cached Montgomery bits), the thread safety of some functions don't match the usual const/non-const distinction. Fix const-ness where easy and document it otherwise. Change-Id: If2037a4874d7580cc79b18ee21f12ae0f47db7fd Reviewed-on: https://boringssl-review.googlesource.com/31344 Reviewed-by: Ryan Sleevi <rsleevi@chromium.org> Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c index 4feadb7..ed7cc85 100644 --- a/crypto/evp/evp.c +++ b/crypto/evp/evp.c
@@ -176,7 +176,7 @@ return 0; } -int EVP_PKEY_bits(EVP_PKEY *pkey) { +int EVP_PKEY_bits(const EVP_PKEY *pkey) { if (pkey && pkey->ameth && pkey->ameth->pkey_bits) { return pkey->ameth->pkey_bits(pkey); } @@ -225,7 +225,7 @@ return EVP_PKEY_assign(pkey, EVP_PKEY_RSA, key); } -RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) { +RSA *EVP_PKEY_get0_RSA(const EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_RSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_RSA_KEY); return NULL; @@ -233,7 +233,7 @@ return pkey->pkey.rsa; } -RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey) { +RSA *EVP_PKEY_get1_RSA(const EVP_PKEY *pkey) { RSA *rsa = EVP_PKEY_get0_RSA(pkey); if (rsa != NULL) { RSA_up_ref(rsa); @@ -253,7 +253,7 @@ return EVP_PKEY_assign(pkey, EVP_PKEY_DSA, key); } -DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey) { +DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_DSA) { OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DSA_KEY); return NULL; @@ -261,7 +261,7 @@ return pkey->pkey.dsa; } -DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey) { +DSA *EVP_PKEY_get1_DSA(const EVP_PKEY *pkey) { DSA *dsa = EVP_PKEY_get0_DSA(pkey); if (dsa != NULL) { DSA_up_ref(dsa); @@ -281,7 +281,7 @@ return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key); } -EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) { +EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_EC) { OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_EC_KEY_KEY); return NULL; @@ -289,7 +289,7 @@ return pkey->pkey.ec; } -EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) { +EC_KEY *EVP_PKEY_get1_EC_KEY(const EVP_PKEY *pkey) { EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey); if (ec_key != NULL) { EC_KEY_up_ref(ec_key); @@ -297,8 +297,8 @@ return ec_key; } -DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey) { return NULL; } -DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey) { return NULL; } +DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey) { return NULL; } +DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey) { return NULL; } int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { if (!EVP_PKEY_set_type(pkey, type)) {
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c index 81c7a71..383e2f9 100644 --- a/crypto/evp/evp_asn1.c +++ b/crypto/evp/evp_asn1.c
@@ -331,7 +331,7 @@ } } -int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) { +int i2d_PublicKey(const EVP_PKEY *key, uint8_t **outp) { switch (key->type) { case EVP_PKEY_RSA: return i2d_RSAPublicKey(key->pkey.rsa, outp);
diff --git a/crypto/fipsmodule/rsa/padding.c b/crypto/fipsmodule/rsa/padding.c index ce3df7a..b7998fe 100644 --- a/crypto/fipsmodule/rsa/padding.c +++ b/crypto/fipsmodule/rsa/padding.c
@@ -480,7 +480,7 @@ static const uint8_t kPSSZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0}; -int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, +int RSA_verify_PKCS1_PSS_mgf1(const RSA *rsa, const uint8_t *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash, const uint8_t *EM, int sLen) { int i; @@ -579,7 +579,7 @@ return ret; } -int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, +int RSA_padding_add_PKCS1_PSS_mgf1(const RSA *rsa, unsigned char *EM, const unsigned char *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash, int sLenRequested) {
diff --git a/decrepit/rsa/rsa_decrepit.c b/decrepit/rsa/rsa_decrepit.c index c4ef5b6..54be9b2 100644 --- a/decrepit/rsa/rsa_decrepit.c +++ b/decrepit/rsa/rsa_decrepit.c
@@ -85,13 +85,13 @@ return NULL; } -int RSA_padding_add_PKCS1_PSS(RSA *rsa, uint8_t *EM, const uint8_t *mHash, +int RSA_padding_add_PKCS1_PSS(const RSA *rsa, uint8_t *EM, const uint8_t *mHash, const EVP_MD *Hash, int sLen) { return RSA_padding_add_PKCS1_PSS_mgf1(rsa, EM, mHash, Hash, NULL, sLen); } -int RSA_verify_PKCS1_PSS(RSA *rsa, const uint8_t *mHash, const EVP_MD *Hash, - const uint8_t *EM, int sLen) { +int RSA_verify_PKCS1_PSS(const RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, const uint8_t *EM, int sLen) { return RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, Hash, NULL, EM, sLen); }
diff --git a/include/openssl/ec_key.h b/include/openssl/ec_key.h index a94116c..6944049 100644 --- a/include/openssl/ec_key.h +++ b/include/openssl/ec_key.h
@@ -84,6 +84,12 @@ // EC key objects. +// +// An |EC_KEY| object represents a public or private EC key. A given object may +// be used concurrently on multiple threads by non-mutating functions, provided +// no other thread is concurrently calling a mutating function. Unless otherwise +// documented, functions which take a |const| pointer are non-mutating and +// functions which take a non-|const| pointer are mutating. // EC_KEY_new returns a fresh |EC_KEY| object or NULL on error. OPENSSL_EXPORT EC_KEY *EC_KEY_new(void); @@ -102,7 +108,8 @@ // EC_KEY_dup returns a fresh copy of |src| or NULL on error. OPENSSL_EXPORT EC_KEY *EC_KEY_dup(const EC_KEY *src); -// EC_KEY_up_ref increases the reference count of |key| and returns one. +// EC_KEY_up_ref increases the reference count of |key| and returns one. It does +// not mutate |key| for thread-safety purposes and may be used concurrently. OPENSSL_EXPORT int EC_KEY_up_ref(EC_KEY *key); // EC_KEY_is_opaque returns one if |key| is opaque and doesn't expose its key
diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 3719d7f..9b00a07 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h
@@ -80,6 +80,12 @@ // Public key objects. +// +// An |EVP_PKEY| object represents a public or private key. A given object may +// be used concurrently on multiple threads by non-mutating functions, provided +// no other thread is concurrently calling a mutating function. Unless otherwise +// documented, functions which take a |const| pointer are non-mutating and +// functions which take a non-|const| pointer are mutating. // EVP_PKEY_new creates a new, empty public-key object and returns it or NULL // on allocation failure. @@ -89,7 +95,9 @@ // itself. OPENSSL_EXPORT void EVP_PKEY_free(EVP_PKEY *pkey); -// EVP_PKEY_up_ref increments the reference count of |pkey| and returns one. +// EVP_PKEY_up_ref increments the reference count of |pkey| and returns one. It +// does not mutate |pkey| for thread-safety purposes and may be used +// concurrently. OPENSSL_EXPORT int EVP_PKEY_up_ref(EVP_PKEY *pkey); // EVP_PKEY_is_opaque returns one if |pkey| is opaque. Opaque keys are backed by @@ -121,7 +129,7 @@ // EVP_PKEY_bits returns the "size", in bits, of |pkey|. For an RSA key, this // returns the bit length of the modulus. For an EC key, this returns the bit // length of the group order. -OPENSSL_EXPORT int EVP_PKEY_bits(EVP_PKEY *pkey); +OPENSSL_EXPORT int EVP_PKEY_bits(const EVP_PKEY *pkey); // EVP_PKEY_id returns the type of |pkey|, which is one of the |EVP_PKEY_*| // values. @@ -141,21 +149,26 @@ // zero if |key| is NULL. The |get1| functions return a fresh reference to the // underlying object or NULL if |pkey| is not of the correct type. The |get0| // functions behave the same but return a non-owning pointer. +// +// The |get0| and |get1| functions take |const| pointers and are thus +// non-mutating for thread-safety purposes, but mutating functions on the +// returned lower-level objects are considered to also mutate the |EVP_PKEY| and +// may not be called concurrently with other operations on the |EVP_PKEY|. OPENSSL_EXPORT int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key); OPENSSL_EXPORT int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key); -OPENSSL_EXPORT RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); -OPENSSL_EXPORT RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); +OPENSSL_EXPORT RSA *EVP_PKEY_get0_RSA(const EVP_PKEY *pkey); +OPENSSL_EXPORT RSA *EVP_PKEY_get1_RSA(const EVP_PKEY *pkey); OPENSSL_EXPORT int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key); OPENSSL_EXPORT int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key); -OPENSSL_EXPORT DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey); -OPENSSL_EXPORT DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); +OPENSSL_EXPORT DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey); +OPENSSL_EXPORT DSA *EVP_PKEY_get1_DSA(const EVP_PKEY *pkey); OPENSSL_EXPORT int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); OPENSSL_EXPORT int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); -OPENSSL_EXPORT EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey); -OPENSSL_EXPORT EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); +OPENSSL_EXPORT EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey); +OPENSSL_EXPORT EC_KEY *EVP_PKEY_get1_EC_KEY(const EVP_PKEY *pkey); // EVP_PKEY_new_ed25519_public returns a newly allocated |EVP_PKEY| wrapping an // Ed25519 public key, or NULL on allocation error. @@ -240,6 +253,9 @@ // Ed25519, |type| should be NULL. The |EVP_MD_CTX| itself is unused but is // present so the API is uniform. See |EVP_DigestSign|. // +// This function does not mutate |pkey| for thread-safety purposes and may be +// used concurrently with other non-mutating functions on |pkey|. +// // It returns one on success, or zero on error. OPENSSL_EXPORT int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, @@ -293,6 +309,9 @@ // Ed25519, |type| should be NULL. The |EVP_MD_CTX| itself is unused but is // present so the API is uniform. See |EVP_DigestVerify|. // +// This function does not mutate |pkey| for thread-safety purposes and may be +// used concurrently with other non-mutating functions on |pkey|. +// // It returns one on success, or zero on error. OPENSSL_EXPORT int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, @@ -353,7 +372,9 @@ // It returns one on success and zero otherwise. // // It does not modify |ctx|, thus it's possible to continue to use |ctx| in -// order to sign a longer message. +// order to sign a longer message. It also does not mutate |pkey| for +// thread-safety purposes and may be used concurrently with other non-mutating +// functions on |pkey|. OPENSSL_EXPORT int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, unsigned int *out_sig_len, EVP_PKEY *pkey); @@ -386,7 +407,9 @@ // It returns one on success and zero otherwise. // // It does not modify |ctx|, thus it's possible to continue to use |ctx| in -// order to sign a longer message. +// order to verify a longer message. It also does not mutate |pkey| for +// thread-safety purposes and may be used concurrently with other non-mutating +// functions on |pkey|. OPENSSL_EXPORT int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len, EVP_PKEY *pkey); @@ -779,7 +802,7 @@ // EC keys are serialized as an EC point per SEC 1. // // Use |RSA_marshal_public_key| or |EC_POINT_point2cbb| instead. -OPENSSL_EXPORT int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp); +OPENSSL_EXPORT int i2d_PublicKey(const EVP_PKEY *key, uint8_t **outp); // d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at // |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in @@ -804,10 +827,10 @@ long len); // EVP_PKEY_get0_DH returns NULL. -OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey); +OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey); // EVP_PKEY_get1_DH returns NULL. -OPENSSL_EXPORT DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey); +OPENSSL_EXPORT DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey); // Preprocessor compatibility section (hidden).
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index 7ed5dce..98bb31c 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h
@@ -72,8 +72,14 @@ // Allocation and destruction. +// +// An |RSA| object represents a public or private RSA key. A given object may be +// used concurrently on multiple threads by non-mutating functions, provided no +// other thread is concurrently calling a mutating function. Unless otherwise +// documented, functions which take a |const| pointer are non-mutating and +// functions which take a non-|const| pointer are mutating. -// RSA_new returns a new, empty RSA object or NULL on error. +// RSA_new returns a new, empty |RSA| object or NULL on error. OPENSSL_EXPORT RSA *RSA_new(void); // RSA_new_method acts the same as |RSA_new| but takes an explicit |ENGINE|. @@ -83,7 +89,8 @@ // reference count drops to zero. OPENSSL_EXPORT void RSA_free(RSA *rsa); -// RSA_up_ref increments the reference count of |rsa| and returns one. +// RSA_up_ref increments the reference count of |rsa| and returns one. It does +// not mutate |rsa| for thread-safety purposes and may be used concurrently. OPENSSL_EXPORT int RSA_up_ref(RSA *rsa); @@ -164,6 +171,9 @@ // Encryption / Decryption +// +// These functions are considered non-mutating for thread-safety purposes and +// may be used concurrently. // Padding types for encryption. #define RSA_PKCS1_PADDING 1 @@ -231,6 +241,9 @@ // Signing / Verification +// +// These functions are considered non-mutating for thread-safety purposes and +// may be used concurrently. // RSA_sign signs |in_len| bytes of digest from |in| with |rsa| using // RSASSA-PKCS1-v1_5. It writes, at most, |RSA_size(rsa)| bytes to |out|. On @@ -372,8 +385,9 @@ // returns zero then a more detailed error is available on the error queue. OPENSSL_EXPORT int RSA_check_key(const RSA *rsa); -// RSA_check_fips performs public key validity tests on |key|. It returns one -// if they pass and zero otherwise. Opaque keys always fail. +// RSA_check_fips performs public key validity tests on |key|. It returns one if +// they pass and zero otherwise. Opaque keys always fail. This function does not +// mutate |rsa| for thread-safety purposes and may be used concurrently. OPENSSL_EXPORT int RSA_check_fips(RSA *key); // RSA_verify_PKCS1_PSS_mgf1 verifies that |EM| is a correct PSS padding of @@ -390,7 +404,8 @@ // // This function implements only the low-level padding logic. Use // |RSA_verify_pss_mgf1| instead. -OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, +OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(const RSA *rsa, + const uint8_t *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash, const uint8_t *EM, int sLen); @@ -407,7 +422,7 @@ // // This function implements only the low-level padding logic. Use // |RSA_sign_pss_mgf1| instead. -OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, +OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(const RSA *rsa, uint8_t *EM, const uint8_t *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash, @@ -567,7 +582,7 @@ // // This function implements only the low-level padding logic. Use // |RSA_sign_pss_mgf1| instead. -OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS(RSA *rsa, uint8_t *EM, +OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS(const RSA *rsa, uint8_t *EM, const uint8_t *mHash, const EVP_MD *Hash, int sLen); @@ -576,7 +591,7 @@ // // This function implements only the low-level padding logic. Use // |RSA_verify_pss_mgf1| instead. -OPENSSL_EXPORT int RSA_verify_PKCS1_PSS(RSA *rsa, const uint8_t *mHash, +OPENSSL_EXPORT int RSA_verify_PKCS1_PSS(const RSA *rsa, const uint8_t *mHash, const EVP_MD *Hash, const uint8_t *EM, int sLen);