//! ```ignore //! // Private-key information shall have ASN.1 type PrivateKeyInfo //! PrivateKeyInfo ::= SEQUENCE { //! version Version, //! privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, //! privateKey PrivateKey, //! attributes [0] IMPLICIT Attributes OPTIONAL //! } //! //! // version is the syntax version number, for compatibility with future revisions of the spec. //! // It shall be 0 for this version. //! Version ::= INTEGER //! //! // privateKeyAlgorithm identifies the private-key algorithm. One example of a private-key //! // algorithm is PKCS #1's rsaEncryption [PKCS#1] //! // //! // A type that identifies an algorithm (by object identifier) and any associated parameters. //! // This type is defined in [X.509](https://tools.ietf.org/html/rfc5208#ref-X.509) //! PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier //! //! // privateKey is an octet string whose contents are the value of the private key. The //! // interpretation of the contents is defined in the registration of the private-key algorithm. //! // For an RSA private key, for example, the ocntents are a BER encodeing of a value of type //! // RSAPrivateKey. //! PrivateKey ::= OCTET STRING //! //! // attributes is a set of attributes. These are the extended information that is encrypted //! // along with the private-key information. //! Attributes ::= SET OF Attribute //! ``` use log::debug; use num_bigint_dig::{traits::ModInverse, BigUint}; use num_traits::identities::One; use rsa::{PublicKey, RSAPrivateKey}; use super::*; impl KeyExt for RSAPrivateKey { fn to_pem_pkcs8(&self) -> Result { let bytes = write_pkcs1(self).ok_or(KeyError::Serialize)?; let oid = yasna::models::ObjectIdentifier::from_slice(&RSA_OID); let contents = yasna::construct_der(|writer| { writer.write_sequence(|writer| { writer.next().write_i64(0); // version is 0 writer.next().write_sequence(|writer| { writer.next().write_oid(&oid); writer.next().write_null(); }); writer.next().write_bytes(&bytes); }); }); let p = pem::Pem { tag: "PRIVATE KEY".to_owned(), contents, }; Ok(pem::encode(&p)) } fn from_pem_pkcs8(pem: &str) -> Result { let data = pem::parse(pem).map_err(|_| KeyError::Pem)?; if data.tag != "PRIVATE KEY" { return Err(KeyError::Kind); } let expected_oid = yasna::models::ObjectIdentifier::from_slice(&RSA_OID); let pkey = yasna::parse_der(&data.contents, |reader| { // Read the outer DER-encoded value reader.read_sequence(|reader| { // Read Version ::= INTEGER debug!("Parsing algorithm ID"); let version = reader.next().read_i64()?; // PKCS#8 defines version == 0 if version != 0 { return Err(yasna::ASN1Error::new(yasna::ASN1ErrorKind::Invalid)); } // Read AlgorithmIdentifier ::= AlgorithmIdentifier debug!("Parsing oid"); let oid = reader.next().read_sequence(|reader| { let oid = reader.next().read_oid()?; reader.next().read_null()?; Ok(oid) })?; // RSA defines OID == 1.2.840.113549.1.1.1 if oid != expected_oid { return Err(yasna::ASN1Error::new(yasna::ASN1ErrorKind::Invalid)); } // Read PrivateKey ::= OCTET STRING debug!("Parsing bytes"); let bytes = reader.next().read_bytes()?; // TODO: Read Attributes ::= SET OF Attribute parse_pkcs1(&bytes) }) })?; pkey.validate().map_err(|_| KeyError::Validate)?; Ok(pkey) } fn to_pem_pkcs1(&self) -> Result { let contents = write_pkcs1(self).ok_or(KeyError::Serialize)?; let p = pem::Pem { tag: "RSA PRIVATE KEY".to_owned(), contents, }; Ok(pem::encode(&p)) } fn from_pem_pkcs1(pem: &str) -> Result { let data = pem::parse(pem).map_err(|_| KeyError::Pem)?; if data.tag != "RSA PRIVATE KEY" { return Err(KeyError::Kind); } let pkey = parse_pkcs1(&data.contents)?; pkey.validate().map_err(|_| KeyError::Validate)?; Ok(pkey) } } fn write_pkcs1(rsa: &RSAPrivateKey) -> Option> { let exp1 = rsa.d() % (rsa.primes()[0].clone() - BigUint::one()); let exp2 = rsa.d() % (rsa.primes()[1].clone() - BigUint::one()); let coeff = rsa.primes()[0] .clone() .mod_inverse(rsa.primes()[1].clone())?; Some(yasna::construct_der(|writer| { writer.write_sequence(|writer| { writer.next().write_i64(0); writer.next().write_biguint(&from_dig(rsa.n())); writer.next().write_biguint(&from_dig(rsa.e())); writer.next().write_biguint(&from_dig(rsa.d())); writer.next().write_biguint(&from_dig(&rsa.primes()[0])); writer.next().write_biguint(&from_dig(&rsa.primes()[1])); writer.next().write_biguint(&from_dig(&exp1)); writer.next().write_biguint(&from_dig(&exp2)); writer.next().write_bigint(&int_from_dig(&coeff)); }) })) } fn parse_pkcs1(bytes: &[u8]) -> Result { yasna::parse_der(bytes, |reader| { reader.read_sequence(|reader| { let version = reader.next().read_i64()?; // version 0 (two primes) is the only supported RSAPrivateKey version, 1 (multi-prime) is unsupported if version != 0 { return Err(yasna::ASN1Error::new(yasna::ASN1ErrorKind::Invalid)); } let modulus = reader.next().read_biguint()?; let pubexp = reader.next().read_biguint()?; let privexp = reader.next().read_biguint()?; let prime1 = reader.next().read_biguint()?; let prime2 = reader.next().read_biguint()?; // These need to be read or else the parser will error let _exp1 = reader.next().read_biguint()?; let _exp2 = reader.next().read_biguint()?; let _coeff = reader.next().read_biguint()?; let pkey = RSAPrivateKey::from_components( to_dig(&modulus), to_dig(&pubexp), to_dig(&privexp), vec![to_dig(&prime1), to_dig(&prime2)], ); Ok(pkey) }) }) }