Skip to content
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

[DOC] enhance RDoc for exporting pkeys #645

Merged
merged 3 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions ext/openssl/ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)

while (1) {
/*
* when the flag is nonzero, this passphrase
* when the flag is nonzero, this password
* will be used to perform encryption; otherwise it will
* be used to perform decryption.
*/
Expand Down Expand Up @@ -669,23 +669,21 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* key = OpenSSL::PKey::RSA.new 2048
*
* open 'private_key.pem', 'w' do |io| io.write key.to_pem end
* open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end
* File.write 'private_key.pem', key.private_to_pem
* File.write 'public_key.pem', key.public_to_pem
*
* === Exporting a Key
*
* Keys saved to disk without encryption are not secure as anyone who gets
* ahold of the key may use it unless it is encrypted. In order to securely
* export a key you may export it with a pass phrase.
* export a key you may export it with a password.
*
* cipher = OpenSSL::Cipher.new 'aes-256-cbc'
* pass_phrase = 'my secure pass phrase goes here'
* password = 'my secure password goes here'
*
* key_secure = key.export cipher, pass_phrase
* key_secure = key.private_to_pem cipher, password
*
* open 'private.secure.pem', 'w' do |io|
* io.write key_secure
* end
* File.write 'private.secure.pem', key_secure
*
* OpenSSL::Cipher.ciphers returns a list of available ciphers.
*
Expand All @@ -705,13 +703,13 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Loading an Encrypted Key
*
* OpenSSL will prompt you for your pass phrase when loading an encrypted key.
* If you will not be able to type in the pass phrase you may provide it when
* OpenSSL will prompt you for your password when loading an encrypted key.
* If you will not be able to type in the password you may provide it when
* loading the key:
*
* key4_pem = File.read 'private.secure.pem'
* pass_phrase = 'my secure pass phrase goes here'
* key4 = OpenSSL::PKey.read key4_pem, pass_phrase
* password = 'my secure password goes here'
* key4 = OpenSSL::PKey.read key4_pem, password
*
* == RSA Encryption
*
Expand Down Expand Up @@ -943,12 +941,12 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* not readable by other users.
*
* ca_key = OpenSSL::PKey::RSA.new 2048
* pass_phrase = 'my secure pass phrase goes here'
* password = 'my secure password goes here'
*
* cipher = OpenSSL::Cipher.new 'aes-256-cbc'
* cipher = 'aes-256-cbc'
*
* open 'ca_key.pem', 'w', 0400 do |io|
* io.write ca_key.export(cipher, pass_phrase)
* io.write ca_key.private_to_pem(cipher, password)
* end
*
* === CA Certificate
Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/ossl_kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ static VALUE mKDF, eKDF;
* (https://tools.ietf.org/html/rfc2898#section-5.2).
*
* === Parameters
* pass :: The passphrase.
* pass :: The password.
* salt :: The salt. Salts prevent attacks based on dictionaries of common
* passwords and attacks based on rainbow tables. It is a public
* value that can be safely stored along with the password (e.g.
Expand Down
18 changes: 18 additions & 0 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,18 @@ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
*
* Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
* for more details.
*
* An unencrypted PEM-encoded key will look like:
*
* -----BEGIN PRIVATE KEY-----
* [...]
* -----END PRIVATE KEY-----
*
* An encrypted PEM-encoded key will look like:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* [...]
* -----END ENCRYPTED PRIVATE KEY-----
*/
static VALUE
ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
Expand Down Expand Up @@ -858,6 +870,12 @@ ossl_pkey_public_to_der(VALUE self)
* pkey.public_to_pem -> string
*
* Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
*
* A PEM-encoded key will look like:
*
* -----BEGIN PUBLIC KEY-----
* [...]
* -----END PUBLIC KEY-----
*/
static VALUE
ossl_pkey_public_to_pem(VALUE self)
Expand Down
29 changes: 22 additions & 7 deletions ext/openssl/ossl_pkey_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,20 @@ ossl_dh_is_private(VALUE self)
* dh.to_pem -> aString
* dh.to_s -> aString
*
* Encodes this DH to its PEM encoding. Note that any existing per-session
* public/private keys will *not* get encoded, just the Diffie-Hellman
* parameters will be encoded.
* Serializes the DH parameters to a PEM-encoding.
*
* Note that any existing per-session public/private keys will *not* get
* encoded, just the Diffie-Hellman parameters will be encoded.
*
* PEM-encoded parameters will look like:
*
* -----BEGIN DH PARAMETERS-----
* [...]
* -----END DH PARAMETERS-----
*
* See also #public_to_pem (X.509 SubjectPublicKeyInfo) and
* #private_to_pem (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for
* serialization with the private or public key components.
*/
static VALUE
ossl_dh_export(VALUE self)
Expand All @@ -244,10 +255,14 @@ ossl_dh_export(VALUE self)
* call-seq:
* dh.to_der -> aString
*
* Encodes this DH to its DER encoding. Note that any existing per-session
* public/private keys will *not* get encoded, just the Diffie-Hellman
* parameters will be encoded.

* Serializes the DH parameters to a DER-encoding
*
* Note that any existing per-session public/private keys will *not* get
* encoded, just the Diffie-Hellman parameters will be encoded.
*
* See also #public_to_der (X.509 SubjectPublicKeyInfo) and
* #private_to_der (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for
* serialization with the private or public key components.
*/
static VALUE
ossl_dh_to_der(VALUE self)
Expand Down
65 changes: 57 additions & 8 deletions ext/openssl/ossl_pkey_dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,58 @@ ossl_dsa_is_private(VALUE self)
* dsa.to_pem([cipher, password]) -> aString
* dsa.to_s([cipher, password]) -> aString
*
* Encodes this DSA to its PEM encoding.
* Serializes a private or public key to a PEM-encoding.
*
* === Parameters
* * _cipher_ is an OpenSSL::Cipher.
* * _password_ is a string containing your password.
* [When the key contains public components only]
*
* === Examples
* DSA.to_pem -> aString
* DSA.to_pem(cipher, 'mypassword') -> aString
* Serializes it into an X.509 SubjectPublicKeyInfo.
* The parameters _cipher_ and _password_ are ignored.
*
* A PEM-encoded key will look like:
*
* -----BEGIN PUBLIC KEY-----
* [...]
* -----END PUBLIC KEY-----
*
* Consider using #public_to_pem instead. This serializes the key into an
* X.509 SubjectPublicKeyInfo regardless of whether it is a public key
* or a private key.
*
* [When the key contains private components, and no parameters are given]
*
* Serializes it into a traditional \OpenSSL DSAPrivateKey.
*
* A PEM-encoded key will look like:
*
* -----BEGIN DSA PRIVATE KEY-----
* [...]
* -----END DSA PRIVATE KEY-----
*
* [When the key contains private components, and _cipher_ and _password_ are given]
*
* Serializes it into a traditional \OpenSSL DSAPrivateKey and encrypts it in
* OpenSSL's traditional PEM encryption format.
* _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
* instance of OpenSSL::Cipher.
*
* An encrypted PEM-encoded key will look like:
*
* -----BEGIN DSA PRIVATE KEY-----
* Proc-Type: 4,ENCRYPTED
* DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
*
* [...]
* -----END DSA PRIVATE KEY-----
*
* Note that this format uses MD5 to derive the encryption key, and hence
* will not be available on FIPS-compliant systems.
*
* <b>This method is kept for compatibility.</b>
* This should only be used when the traditional, non-standard \OpenSSL format
* is required.
*
* Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
* (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
*/
static VALUE
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
Expand All @@ -238,8 +280,15 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* dsa.to_der -> aString
*
* Encodes this DSA to its DER encoding.
* Serializes a private or public key to a DER-encoding.
*
* See #to_pem for details.
*
* <b>This method is kept for compatibility.</b>
* This should only be used when the traditional, non-standard \OpenSSL format
* is required.
*
* Consider using #public_to_der or #private_to_der instead.
*/
static VALUE
ossl_dsa_to_der(VALUE self)
Expand Down
70 changes: 63 additions & 7 deletions ext/openssl/ossl_pkey_ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,13 +400,61 @@ static VALUE ossl_ec_key_is_private(VALUE self)

/*
* call-seq:
* key.export([cipher, pass_phrase]) => String
* key.to_pem([cipher, pass_phrase]) => String
* key.export([cipher, password]) => String
* key.to_pem([cipher, password]) => String
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you replace the variable pass_phrase with the password here, do you like to replace the following parts too?

$ grep -r pass_phrase lib/ ext/
ext/openssl/ossl.c: *   pass_phrase = 'my secure pass phrase goes here'
ext/openssl/ossl.c: *   key_secure = key.private_to_pem cipher, pass_phrase
ext/openssl/ossl.c: *   pass_phrase = 'my secure pass phrase goes here'
ext/openssl/ossl.c: *   key4 = OpenSSL::PKey.read key4_pem, pass_phrase
ext/openssl/ossl.c: *   pass_phrase = 'my secure pass phrase goes here'
ext/openssl/ossl.c: *   encryptor.pkcs5_keyivgen pass_phrase, salt
ext/openssl/ossl.c: *   decryptor.pkcs5_keyivgen pass_phrase, salt
ext/openssl/ossl.c: *   pass_phrase = 'my secure pass phrase goes here'
ext/openssl/ossl.c: *     io.write ca_key.private_to_pem(cipher, pass_phrase)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. To my understanding, the words password and /pass.?phrase/ are completely interchangeable, but they haven't been used consistently.

In fact, RFCs and OpenSSL man pages are inconsistent in word choice.

  • RFC 8018: PKCS#5 (PBKDF2, OpenSSL::KDF.pbkdf2_hmac) which is used by PKCS#8's encryption uses the word "password".
  • RFC 7292: PKCS#12 (OpenSSL::PKCS12) also uses "password".
  • RFC 7914: scrypt (OpenSSL::KDF.scrypt) describes itself as a "password-based key derivation function", while it names the input parameter as the "passphrase".
  • OpenSSL's man pages appear to prefer "passphrase" in recent years, but OpenSSL has both functions named "password" and "passphrase". Notably, OpenSSL 3.0.0 added two functions named OSSL_ENCODER_CTX_set_pem_password_cb() and OSSL_ENCODER_CTX_set_passphrase_cb() which appear to serve the same purpose (!?).

I will push a new change to replace all /pass.?phrase/ with "password", except scrypt where "passphrase" is more appropriate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Thanks for explaining it. OK. I see that you originally named the variables of the functions referring to the words used in the RFC documents.

I will push a new change to replace all /pass.?phrase/ with "password", except scrypt where "passphrase" is more appropriate.

It sounds good to me!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced the occurrences of "passphrase" with "password" except those in the OpenSSL::Cipher#pkcs5_keyivgen example, which I started to think having the example itself does harm (#647):

ext/openssl/ossl.c: * encryptor.pkcs5_keyivgen pass_phrase, salt
ext/openssl/ossl.c: * decryptor.pkcs5_keyivgen pass_phrase, salt

*
* Outputs the EC key in PEM encoding. If _cipher_ and _pass_phrase_ are given
* they will be used to encrypt the key. _cipher_ must be an OpenSSL::Cipher
* instance. Note that encryption will only be effective for a private key,
* public keys will always be encoded in plain text.
* Serializes a private or public key to a PEM-encoding.
*
* [When the key contains public components only]
*
* Serializes it into an X.509 SubjectPublicKeyInfo.
* The parameters _cipher_ and _password_ are ignored.
*
* A PEM-encoded key will look like:
*
* -----BEGIN PUBLIC KEY-----
* [...]
* -----END PUBLIC KEY-----
*
* Consider using #public_to_pem instead. This serializes the key into an
* X.509 SubjectPublicKeyInfo regardless of whether it is a public key
* or a private key.
*
* [When the key contains private components, and no parameters are given]
*
* Serializes it into a SEC 1/RFC 5915 ECPrivateKey.
*
* A PEM-encoded key will look like:
*
* -----BEGIN EC PRIVATE KEY-----
* [...]
* -----END EC PRIVATE KEY-----
*
* [When the key contains private components, and _cipher_ and _password_ are given]
*
* Serializes it into a SEC 1/RFC 5915 ECPrivateKey
* and encrypts it in OpenSSL's traditional PEM encryption format.
* _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
* instance of OpenSSL::Cipher.
*
* An encrypted PEM-encoded key will look like:
*
* -----BEGIN EC PRIVATE KEY-----
* Proc-Type: 4,ENCRYPTED
* DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
*
* [...]
* -----END EC PRIVATE KEY-----
*
* Note that this format uses MD5 to derive the encryption key, and hence
* will not be available on FIPS-compliant systems.
*
* <b>This method is kept for compatibility.</b>
* This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is
* required.
*
* Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
* (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
*/
static VALUE
ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
Expand All @@ -426,7 +474,15 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* key.to_der => String
*
* See the OpenSSL documentation for i2d_ECPrivateKey_bio()
* Serializes a private or public key to a DER-encoding.
*
* See #to_pem for details.
*
* <b>This method is kept for compatibility.</b>
* This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is
* required.
*
* Consider using #public_to_der or #private_to_der instead.
*/
static VALUE
ossl_ec_key_to_der(VALUE self)
Expand Down
Loading