It seems that ECC keys generated by OpenSSL can be between 30 and 33 bytes long whereas OpenSK code expects a fixed size of 32 bytes. This variation could cause Travis CI to fail but also invalid ECC keys to be flashed, causing the authenticator to not work.
101 lines
3.6 KiB
Rust
101 lines
3.6 KiB
Rust
// Copyright 2019 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
extern crate openssl;
|
|
|
|
use openssl::asn1;
|
|
use openssl::ec;
|
|
use openssl::nid::Nid;
|
|
use openssl::pkey::PKey;
|
|
use openssl::x509;
|
|
use std::env;
|
|
use std::fs::File;
|
|
use std::io::Write;
|
|
use std::path::Path;
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=crypto_data/opensk.key");
|
|
println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");
|
|
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
|
|
let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
|
|
let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");
|
|
|
|
// Load the OpenSSL PEM ECC key
|
|
let ecc_data = include_bytes!("crypto_data/opensk.key");
|
|
let pkey = ec::EcKey::private_key_from_pem(ecc_data)
|
|
.ok()
|
|
.expect("Failed to load OpenSK private key file");
|
|
|
|
// Check key validity
|
|
pkey.check_key().unwrap();
|
|
assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));
|
|
|
|
// Private keys generated by OpenSSL have variable size but we only handle
|
|
// constant size. Serialization is done in big endian so if the size is less
|
|
// than 32 bytes, we need to prepend with null bytes.
|
|
// If the size is 33 bytes, this means the serialized BigInt is negative.
|
|
// Any other size is invalid.
|
|
let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
|
|
let priv_key_vec = pkey.private_key().to_vec();
|
|
let key_len = priv_key_vec.len();
|
|
|
|
assert!(
|
|
key_len >= 30,
|
|
"Invalid private key (too small): {} ({:#?})",
|
|
priv_key_hex,
|
|
priv_key_vec,
|
|
);
|
|
assert!(
|
|
key_len <= 33,
|
|
"Invalid private key (too big): {} ({:#?})",
|
|
priv_key_hex,
|
|
priv_key_vec,
|
|
);
|
|
|
|
// Copy OpenSSL generated key to our vec, starting from the end
|
|
let mut output_vec = [0u8; 32];
|
|
let min_key_len = std::cmp::min(key_len, 32);
|
|
output_vec[32usize.saturating_sub(min_key_len)..]
|
|
.copy_from_slice(&priv_key_vec[key_len.saturating_sub(min_key_len)..]);
|
|
|
|
// Create the raw private key out of the OpenSSL data
|
|
let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
|
|
priv_key_bin_file.write_all(&output_vec).unwrap();
|
|
|
|
// Convert the PEM certificate to DER and extract the serial for AAGUID
|
|
let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
|
|
let cert = x509::X509::from_pem(input_pem_cert)
|
|
.ok()
|
|
.expect("Failed to load OpenSK certificate");
|
|
|
|
// Do some sanity check on the certificate
|
|
assert!(cert
|
|
.public_key()
|
|
.unwrap()
|
|
.public_eq(&PKey::from_ec_key(pkey).unwrap()));
|
|
let now = asn1::Asn1Time::days_from_now(0).unwrap();
|
|
assert!(cert.not_after() > now);
|
|
assert!(cert.not_before() <= now);
|
|
|
|
let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
|
|
cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();
|
|
|
|
let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
|
|
let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
|
|
serial.resize(16, 0);
|
|
aaguid_bin_file.write_all(&serial).unwrap();
|
|
}
|