blob: 3a46bdb4bbb864caacfc240df08198b7eb640599 [file] [log] [blame]
//! Helper module for RSA key encoding / decoding.
mod der;
use untrusted::Input;
use self::der::{Tag, Der};
/// Corresponds to `1.2.840.113549.1.1.1 rsaEncryption(PKCS #1)`
const RSA_PKCS1_OID: &'static [u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01];
pub fn convert_to_pkcs1<'a>(input: &[u8]) -> Vec<u8> {
// if we ever move away from `ring`, this needs to do an explicit key size check (>= 2048)
from_pkcs1(input)
.or_else(|| from_spki(input))
.unwrap_or_else(|| input.to_vec())
}
fn from_pkcs1(input: &[u8]) -> Option<Vec<u8>> {
let _input = Input::from(&input);
_input.read_all(der::Error, |i| {
der::nested(i, Tag::Sequence, der::Error, |i| {
let _ = der::positive_integer(i)?;
let _ = der::positive_integer(i)?;
// if the input was already pkcs1, just return it
Ok(input.to_vec())
})
})
.ok()
}
fn from_spki(input: &[u8]) -> Option<Vec<u8>> {
let _input = Input::from(&input);
_input.read_all(der::Error, |i| {
der::nested(i, Tag::Sequence, der::Error, |i| {
der::nested(i, Tag::Sequence, der::Error, |i| {
let oid = der::expect_tag_and_get_value(i, Tag::OID)?;
if oid != Input::from(RSA_PKCS1_OID) {
return Err(der::Error);
}
let _ = der::expect_tag_and_get_value(i, Tag::Null)?;
Ok(())
})?;
der::nested(i, Tag::BitString, der::Error, |i| {
// wtf why
let _ = der::expect_tag_and_get_value(i, Tag::EOC)?;
Ok(i.skip_to_end().iter().cloned().collect())
//der::nested(i, Tag::Sequence, der::Error, |i| {
// let n = der::positive_integer(i)?;
// let e = der::positive_integer(i)?;
// write_pkcs1(n, e)
//})
})
})
})
.ok()
}
#[allow(dead_code)]
fn write_pkcs1(n: Input, e: Input) -> Result<Vec<u8>, der::Error> {
let mut output = Vec::new();
{
let mut _der = Der::new(&mut output);
_der.write_sequence(|_der| {
_der.write_integer(n)?;
_der.write_integer(e)
})?;
}
Ok(output)
}
#[cfg(test)]
mod test {
use super::*;
use pem;
use std::fs::File;
use std::io::Read;
fn read_file(path: &str) -> Vec<u8> {
let mut file = File::open(path).expect("couldn't open file");
let mut buf = Vec::new();
file.read_to_end(&mut buf).expect("couldn't read file");
buf
}
#[test]
fn test_write_pkcs1() {
let contents = read_file("./tests/rsa/pkcs1-1.pub");
let contents = pem::parse(&contents).expect("not PEM").contents;
let n = &[0x00, 0x9d, 0xda, 0x85, 0x17, 0x15, 0x67, 0xab, 0xb1, 0x63, 0x8a, 0x13, 0x01,
0xee, 0xc0, 0x63, 0x7c, 0xc3, 0x08, 0x4b, 0x6d, 0x75, 0xd8, 0x70, 0x74, 0x3d,
0xab, 0x98, 0xef, 0x00, 0xd0, 0xf2, 0x04, 0xe7, 0x7d, 0xb5, 0xa4, 0x08, 0xe3,
0x90, 0xda, 0x4b, 0xe1, 0xd1, 0xff, 0x0f, 0x87, 0x8d, 0x6b, 0x43, 0x58, 0x99,
0x88, 0xf6, 0x99, 0xab, 0xe7, 0x90, 0xfb, 0x2a, 0xa1, 0x3c, 0x2b, 0x0f, 0x24,
0xa4, 0x9e, 0xab, 0xd1, 0xfc, 0xa0, 0xe0, 0xa8, 0x9f, 0x82, 0x48, 0xe5, 0xa7,
0xd2, 0x4d, 0x44, 0xe4, 0x0b, 0x43, 0x66, 0x03, 0x54, 0x8d, 0xdd, 0xc3, 0x0c,
0x26, 0xf5, 0x20, 0x36, 0xbf, 0xae, 0x05, 0x63, 0x9c, 0xf8, 0x81, 0xeb, 0xf7,
0x4a, 0x3a, 0xc4, 0x14, 0xee, 0xce, 0x99, 0x66, 0x9f, 0x3c, 0xe3, 0x18, 0x21,
0x8d, 0x68, 0xe3, 0x0b, 0xb7, 0xb3, 0xf7, 0xca, 0xe1, 0x7c, 0xab, 0xd5, 0x17,
0x6f, 0x50, 0xc1, 0x38, 0x1b, 0xea, 0x62, 0xeb, 0x46, 0x07, 0x95, 0x01, 0xfb,
0xd3, 0x1a, 0xd0, 0xae, 0x1c, 0xe6, 0x53, 0x27, 0x53, 0x2d, 0x08, 0x55, 0xbe,
0xa3, 0xd6, 0xd1, 0x02, 0x14, 0xa4, 0xa2, 0xe1, 0x14, 0xde, 0xa4, 0x0e, 0x54,
0x00, 0xe5, 0x79, 0x2c, 0x4d, 0x93, 0xe8, 0x6b, 0x3c, 0xf6, 0x44, 0x63, 0x85,
0x3c, 0x6f, 0x56, 0xc2, 0x80, 0x02, 0x3f, 0x76, 0xcf, 0x75, 0x46, 0x5f, 0x9a,
0x49, 0x47, 0xdc, 0xe6, 0xe9, 0x9a, 0xc0, 0x6e, 0x34, 0x9e, 0x9f, 0xd2, 0xdf,
0xbc, 0x55, 0xa0, 0x77, 0x61, 0xf3, 0xd5, 0x0c, 0xb8, 0x77, 0xd2, 0x66, 0xd2,
0x24, 0x9a, 0x25, 0xbe, 0x55, 0x1b, 0x4e, 0xbf, 0x3b, 0x82, 0x4c, 0x4f, 0x51,
0x57, 0x7c, 0x8b, 0xf6, 0x38, 0xfe, 0x4d, 0x97, 0x32, 0xa8, 0xc8, 0x3c, 0x69,
0xe5, 0x91, 0x15, 0x2c, 0x75, 0x8d, 0x92, 0xc1, 0xc7, 0x6b];
let e = &[0x01, 0x00, 0x01];
let bytes = write_pkcs1(Input::from(n), Input::from(e));
assert_eq!(bytes, Ok(contents));
}
#[test]
fn pkcs1_noop_conversion_1() {
let contents = read_file("./tests/rsa/pkcs1-1.pub");
let contents = pem::parse(&contents).expect("not PEM").contents;
assert_eq!(convert_to_pkcs1(&contents), contents);
}
#[test]
fn pkcs1_noop_conversion_2() {
let contents = read_file("./tests/rsa/pkcs1-2.pub");
let contents = pem::parse(&contents).expect("not PEM").contents;
assert_eq!(convert_to_pkcs1(&contents), contents);
}
#[test]
fn pkcs1_from_spki_conversion_1() {
let spki = read_file("./tests/rsa/spki-1.pub");
let spki = pem::parse(&spki).expect("not PEM").contents;
let pkcs1 = read_file("./tests/rsa/pkcs1-1.pub");
let pkcs1 = pem::parse(&pkcs1).expect("not PEM").contents;
for (i, (a, b)) in convert_to_pkcs1(&spki).iter().zip(pkcs1.iter()).enumerate() {
println!("{} {} {}", i, a, b);
}
assert!(convert_to_pkcs1(&spki) == pkcs1);
}
#[test]
fn pkcs1_from_spki_conversion_2() {
let spki = read_file("./tests/rsa/spki-2.pub");
let spki = pem::parse(&spki).expect("not PEM").contents;
let pkcs1 = read_file("./tests/rsa/pkcs1-2.pub");
let pkcs1 = pem::parse(&pkcs1).expect("not PEM").contents;
for (i, (a, b)) in convert_to_pkcs1(&spki).iter().zip(pkcs1.iter()).enumerate() {
println!("{} {} {}", i, a, b);
}
assert!(convert_to_pkcs1(&spki) == pkcs1);
}
}