1 //! Construction of `RsaKeyPair` from ASN1. 2 3 use super::super::{keypair, public}; 4 use crate::{ 5 error::{self, KeyRejected}, 6 io::der, 7 pkcs8, 8 }; 9 use core::convert::TryFrom; 10 11 impl keypair::RsaKeyPair { 12 /// Parses an unencrypted PKCS#8-encoded RSA private key. 13 /// 14 /// Only two-prime (not multi-prime) keys are supported. The public modulus 15 /// (n) must be at least 2047 bits. The public modulus must be no larger 16 /// than 4096 bits. It is recommended that the public modulus be exactly 17 /// 2048 or 3072 bits. The public exponent must be at least 65537. 18 /// 19 /// This will generate a 2048-bit RSA private key of the correct form using 20 /// OpenSSL's command line tool: 21 /// 22 /// ```sh 23 /// openssl genpkey -algorithm RSA \ 24 /// -pkeyopt rsa_keygen_bits:2048 \ 25 /// -pkeyopt rsa_keygen_pubexp:65537 | \ 26 /// openssl pkcs8 -topk8 -nocrypt -outform der > rsa-2048-private-key.pk8 27 /// ``` 28 /// 29 /// This will generate a 3072-bit RSA private key of the correct form: 30 /// 31 /// ```sh 32 /// openssl genpkey -algorithm RSA \ 33 /// -pkeyopt rsa_keygen_bits:3072 \ 34 /// -pkeyopt rsa_keygen_pubexp:65537 | \ 35 /// openssl pkcs8 -topk8 -nocrypt -outform der > rsa-3072-private-key.pk8 36 /// ``` 37 /// 38 /// Often, keys generated for use in OpenSSL-based software are stored in 39 /// the Base64 “PEM” format without the PKCS#8 wrapper. Such keys can be 40 /// converted to binary PKCS#8 form using the OpenSSL command line tool like 41 /// this: 42 /// 43 /// ```sh 44 /// openssl pkcs8 -topk8 -nocrypt -outform der \ 45 /// -in rsa-2048-private-key.pem > rsa-2048-private-key.pk8 46 /// ``` 47 /// 48 /// Base64 (“PEM”) PKCS#8-encoded keys can be converted to the binary PKCS#8 49 /// form like this: 50 /// 51 /// ```sh 52 /// openssl pkcs8 -nocrypt -outform der \ 53 /// -in rsa-2048-private-key.pem > rsa-2048-private-key.pk8 54 /// ``` 55 /// 56 /// The private key is validated according to [NIST SP-800-56B rev. 1] 57 /// section 6.4.1.4.3, crt_pkv (Intended Exponent-Creation Method Unknown), 58 /// with the following exceptions: 59 /// 60 /// * Section 6.4.1.2.1, Step 1: Neither a target security level nor an 61 /// expected modulus length is provided as a parameter, so checks 62 /// regarding these expectations are not done. 63 /// * Section 6.4.1.2.1, Step 3: Since neither the public key nor the 64 /// expected modulus length is provided as a parameter, the consistency 65 /// check between these values and the private key's value of n isn't 66 /// done. 67 /// * Section 6.4.1.2.1, Step 5: No primality tests are done, both for 68 /// performance reasons and to avoid any side channels that such tests 69 /// would provide. 70 /// * Section 6.4.1.2.1, Step 6, and 6.4.1.4.3, Step 7: 71 /// * *ring* has a slightly looser lower bound for the values of `p` 72 /// and `q` than what the NIST document specifies. This looser lower 73 /// bound matches what most other crypto libraries do. The check might 74 /// be tightened to meet NIST's requirements in the future. Similarly, 75 /// the check that `p` and `q` are not too close together is skipped 76 /// currently, but may be added in the future. 77 /// - The validity of the mathematical relationship of `dP`, `dQ`, `e` 78 /// and `n` is verified only during signing. Some size checks of `d`, 79 /// `dP` and `dQ` are performed at construction, but some NIST checks 80 /// are skipped because they would be expensive and/or they would leak 81 /// information through side channels. If a preemptive check of the 82 /// consistency of `dP`, `dQ`, `e` and `n` with each other is 83 /// necessary, that can be done by signing any message with the key 84 /// pair. 85 /// 86 /// * `d` is not fully validated, neither at construction nor during 87 /// signing. This is OK as far as *ring*'s usage of the key is 88 /// concerned because *ring* never uses the value of `d` (*ring* always 89 /// uses `p`, `q`, `dP` and `dQ` via the Chinese Remainder Theorem, 90 /// instead). However, *ring*'s checks would not be sufficient for 91 /// validating a key pair for use by some other system; that other 92 /// system must check the value of `d` itself if `d` is to be used. 93 /// 94 /// In addition to the NIST requirements, *ring* requires that `p > q` and 95 /// that `e` must be no more than 33 bits. 96 /// 97 /// See [RFC 5958] and [RFC 3447 Appendix A.1.2] for more details of the 98 /// encoding of the key. 99 /// 100 /// [NIST SP-800-56B rev. 1]: 101 /// http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br1.pdf 102 /// 103 /// [RFC 3447 Appendix A.1.2]: 104 /// https://tools.ietf.org/html/rfc3447#appendix-A.1.2 105 /// 106 /// [RFC 5958]: 107 /// https://tools.ietf.org/html/rfc5958 from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected>108 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> { 109 const RSA_ENCRYPTION: &[u8] = include_bytes!("../../data/alg-rsa-encryption.der"); 110 let (der, _) = pkcs8::unwrap_key_( 111 untrusted::Input::from(&RSA_ENCRYPTION), 112 pkcs8::Version::V1Only, 113 untrusted::Input::from(pkcs8), 114 )?; 115 Self::from_der(der.as_slice_less_safe()) 116 } 117 118 /// Parses an RSA private key that is not inside a PKCS#8 wrapper. 119 /// 120 /// The private key must be encoded as a binary DER-encoded ASN.1 121 /// `RSAPrivateKey` as described in [RFC 3447 Appendix A.1.2]). In all other 122 /// respects, this is just like `from_pkcs8()`. See the documentation for 123 /// `from_pkcs8()` for more details. 124 /// 125 /// It is recommended to use `from_pkcs8()` (with a PKCS#8-encoded key) 126 /// instead. 127 /// 128 /// [RFC 3447 Appendix A.1.2]: 129 /// https://tools.ietf.org/html/rfc3447#appendix-A.1.2 130 /// 131 /// [NIST SP-800-56B rev. 1]: 132 /// http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br1.pdf from_der(input: &[u8]) -> Result<Self, KeyRejected>133 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> { 134 untrusted::Input::from(input).read_all(KeyRejected::invalid_encoding(), |input| { 135 der::nested( 136 input, 137 der::Tag::Sequence, 138 KeyRejected::invalid_encoding(), 139 Self::from_der_reader, 140 ) 141 }) 142 } 143 from_der_reader(input: &mut untrusted::Reader) -> Result<Self, KeyRejected>144 fn from_der_reader(input: &mut untrusted::Reader) -> Result<Self, KeyRejected> { 145 let version = der::small_nonnegative_integer(input) 146 .map_err(|error::Unspecified| KeyRejected::invalid_encoding())?; 147 if version != 0 { 148 return Err(KeyRejected::version_not_supported()); 149 } 150 151 fn nonnegative_integer<'a>( 152 input: &mut untrusted::Reader<'a>, 153 ) -> Result<&'a [u8], KeyRejected> { 154 der::nonnegative_integer(input, 0) 155 .map(|input| input.as_slice_less_safe()) 156 .map_err(|error::Unspecified| KeyRejected::invalid_encoding()) 157 } 158 159 let n = nonnegative_integer(input)?; 160 let e = nonnegative_integer(input)?; 161 let d = nonnegative_integer(input)?; 162 let p = nonnegative_integer(input)?; 163 let q = nonnegative_integer(input)?; 164 let dP = nonnegative_integer(input)?; 165 let dQ = nonnegative_integer(input)?; 166 let qInv = nonnegative_integer(input)?; 167 168 let components = keypair::Components { 169 public_key: public::Components { n, e }, 170 d, 171 p, 172 q, 173 dP, 174 dQ, 175 qInv, 176 }; 177 178 Self::try_from(&components) 179 } 180 } 181