Preliminary x.509 support. This is some of the ugliest code I've ever written, but it works. Ish.
This commit is contained in:
@@ -10,6 +10,7 @@ repository = "https://github.com/acw/simple_crypto"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "^1.2.7"
|
byteorder = "^1.2.7"
|
||||||
|
chrono = "^0.4.6"
|
||||||
cryptonum = { path = "../cryptonum" }
|
cryptonum = { path = "../cryptonum" }
|
||||||
digest = "^0.8.0"
|
digest = "^0.8.0"
|
||||||
hmac = "^0.7.0"
|
hmac = "^0.7.0"
|
||||||
|
|||||||
@@ -20,17 +20,19 @@ pub struct DSAKeyPair<P,L,N>
|
|||||||
pub public: DSAPubKey<P,L>
|
pub public: DSAPubKey<P,L>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DSAKeyGeneration<P>
|
pub trait DSAKeyGeneration
|
||||||
{
|
{
|
||||||
fn generate<G: Rng>(params: &P, rng: &mut G) -> Self;
|
type Params;
|
||||||
|
|
||||||
|
fn generate<G: Rng>(params: &Self::Params, rng: &mut G) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_dsa_pair {
|
macro_rules! generate_dsa_pair {
|
||||||
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
|
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
|
||||||
impl DSAKeyGeneration<$ptype> for DSAKeyPair<$ptype,$ltype,$ntype>
|
impl DSAKeyGeneration for DSAKeyPair<$ptype,$ltype,$ntype>
|
||||||
where
|
|
||||||
DSAPrivKey<$ptype,$ntype>: DSAPrivateKey<$ptype,$ltype,$ntype>,
|
|
||||||
{
|
{
|
||||||
|
type Params = $ptype;
|
||||||
|
|
||||||
fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
|
fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
|
||||||
{
|
{
|
||||||
// 1. N = len(q); L = len(p);
|
// 1. N = len(q); L = len(p);
|
||||||
|
|||||||
@@ -2,11 +2,16 @@ use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
|
|||||||
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
|
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
|
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use utils::TranslateNums;
|
||||||
|
|
||||||
pub trait DSAParameters<L,N>
|
pub trait DSAParameters : ToASN1
|
||||||
{
|
{
|
||||||
fn new(p: L, g: L, q: N) -> Self;
|
type L;
|
||||||
|
type N;
|
||||||
|
|
||||||
|
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
|
||||||
fn generate<G: Rng>(rng: &mut G) -> Self;
|
fn generate<G: Rng>(rng: &mut G) -> Self;
|
||||||
fn n_size() -> usize;
|
fn n_size() -> usize;
|
||||||
fn l_size() -> usize;
|
fn l_size() -> usize;
|
||||||
@@ -25,8 +30,24 @@ macro_rules! generate_parameters {
|
|||||||
pub q: $ntype
|
pub q: $ntype
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DSAParameters<$ltype,$ntype> for $name
|
impl ToASN1 for $name {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let p = ASN1Block::Integer(c, 0, self.p.to_num());
|
||||||
|
let q = ASN1Block::Integer(c, 0, self.q.to_num());
|
||||||
|
let g = ASN1Block::Integer(c, 0, self.g.to_num());
|
||||||
|
Ok(vec![ASN1Block::Sequence(c, 0, vec![p, q, g])])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DSAParameters for $name
|
||||||
{
|
{
|
||||||
|
type L = $ltype;
|
||||||
|
type N = $ntype;
|
||||||
|
|
||||||
fn new(p: $ltype, g: $ltype, q: $ntype) -> $name
|
fn new(p: $ltype, g: $ltype, q: $ntype) -> $name
|
||||||
{
|
{
|
||||||
$name{ p: p, g: g, q: q }
|
$name{ p: p, g: g, q: q }
|
||||||
|
|||||||
@@ -5,13 +5,17 @@ use dsa::params::*;
|
|||||||
use dsa::rfc6979::*;
|
use dsa::rfc6979::*;
|
||||||
use hmac::{Hmac,Mac};
|
use hmac::{Hmac,Mac};
|
||||||
|
|
||||||
pub trait DSAPrivateKey<Params,L,N> {
|
pub trait DSAPrivateKey {
|
||||||
|
type Params;
|
||||||
|
type L;
|
||||||
|
type N;
|
||||||
|
|
||||||
/// Generate a new private key using the given DSA parameters and private
|
/// Generate a new private key using the given DSA parameters and private
|
||||||
/// key value.
|
/// key value.
|
||||||
fn new(params: Params, x: N) -> Self;
|
fn new(params: Self::Params, x: Self::N) -> Self;
|
||||||
/// Generate a DSA signature for the given message, using the appropriate
|
/// Generate a DSA signature for the given message, using the appropriate
|
||||||
/// hash included in the type invocation.
|
/// hash included in the type invocation.
|
||||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<N>
|
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::N>
|
||||||
where
|
where
|
||||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||||
Hmac<Hash>: Mac;
|
Hmac<Hash>: Mac;
|
||||||
@@ -32,8 +36,12 @@ pub enum DSAPrivate {
|
|||||||
|
|
||||||
macro_rules! privkey_impls {
|
macro_rules! privkey_impls {
|
||||||
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
|
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
|
||||||
impl DSAPrivateKey<$ptype,$ltype,$ntype> for DSAPrivKey<$ptype,$ntype>
|
impl DSAPrivateKey for DSAPrivKey<$ptype,$ntype>
|
||||||
{
|
{
|
||||||
|
type Params = $ptype;
|
||||||
|
type L = $ltype;
|
||||||
|
type N = $ntype;
|
||||||
|
|
||||||
fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype>
|
fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype>
|
||||||
{
|
{
|
||||||
DSAPrivKey{ params, x }
|
DSAPrivKey{ params, x }
|
||||||
|
|||||||
@@ -3,17 +3,20 @@ use cryptonum::signed::ModInv;
|
|||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use dsa::params::*;
|
use dsa::params::*;
|
||||||
use dsa::rfc6979::DSASignature;
|
use dsa::rfc6979::DSASignature;
|
||||||
use num::BigInt;
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
|
||||||
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use utils::TranslateNums;
|
use utils::TranslateNums;
|
||||||
|
|
||||||
pub trait DSAPublicKey<Params,L,N> {
|
pub trait DSAPublicKey {
|
||||||
|
type Params : DSAParameters;
|
||||||
|
type L;
|
||||||
|
type N;
|
||||||
|
|
||||||
/// Generate a new public key given the parameters and public value.
|
/// Generate a new public key given the parameters and public value.
|
||||||
fn new(params: Params, y: L) -> Self;
|
fn new(params: Self::Params, y: Self::L) -> Self;
|
||||||
/// Verify the given signature against the given message, using the
|
/// Verify the given signature against the given message, using the
|
||||||
/// appropriate hash function.
|
/// appropriate hash function.
|
||||||
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<N>) -> bool
|
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::N>) -> bool
|
||||||
where Hash: Digest;
|
where Hash: Digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,10 +25,21 @@ pub struct DSAPubKey<Params,L> {
|
|||||||
pub(crate) y: L
|
pub(crate) y: L
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum DSAPublic {
|
||||||
|
DSAPublicL1024N160(DSAPubKey<L1024N160,U1024>),
|
||||||
|
DSAPublicL2048N224(DSAPubKey<L2048N224,U2048>),
|
||||||
|
DSAPublicL2048N256(DSAPubKey<L2048N256,U2048>),
|
||||||
|
DSAPublicL3072N256(DSAPubKey<L3072N256,U3072>)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! pubkey_impls {
|
macro_rules! pubkey_impls {
|
||||||
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
||||||
impl DSAPublicKey<$ptype,$ltype,$ntype> for DSAPubKey<$ptype,$ltype>
|
impl DSAPublicKey for DSAPubKey<$ptype,$ltype>
|
||||||
{
|
{
|
||||||
|
type Params = $ptype;
|
||||||
|
type L = $ltype;
|
||||||
|
type N = $ntype;
|
||||||
|
|
||||||
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
|
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
|
||||||
{
|
{
|
||||||
DSAPubKey{ params, y }
|
DSAPubKey{ params, y }
|
||||||
@@ -72,8 +86,7 @@ macro_rules! pubkey_impls {
|
|||||||
fn to_asn1_class(&self, c: ASN1Class)
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
{
|
{
|
||||||
let uinty = self.y.to_num();
|
let inty = self.y.to_num();
|
||||||
let inty = BigInt::from(uinty);
|
|
||||||
let yblock = ASN1Block::Integer(c, 0, inty);
|
let yblock = ASN1Block::Integer(c, 0, inty);
|
||||||
Ok(vec![yblock])
|
Ok(vec![yblock])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,8 +250,8 @@ fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
|
|||||||
pub enum DSADecodeError {
|
pub enum DSADecodeError {
|
||||||
ASN1Error(ASN1DecodeErr),
|
ASN1Error(ASN1DecodeErr),
|
||||||
NoSignatureFound,
|
NoSignatureFound,
|
||||||
NegativeSigValues,
|
InvalidRValue,
|
||||||
RValueTooBig, SValueTooBig
|
InvalidSValue
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ASN1DecodeErr> for DSADecodeError {
|
impl From<ASN1DecodeErr> for DSADecodeError {
|
||||||
@@ -261,7 +261,7 @@ impl From<ASN1DecodeErr> for DSADecodeError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<N> FromASN1 for DSASignature<N>
|
impl<N> FromASN1 for DSASignature<N>
|
||||||
where N: TranslateNums
|
where N: TranslateNums<BigInt>
|
||||||
{
|
{
|
||||||
type Error = DSADecodeError;
|
type Error = DSADecodeError;
|
||||||
|
|
||||||
@@ -275,16 +275,9 @@ impl<N> FromASN1 for DSASignature<N>
|
|||||||
match (&info[0], &info[1]) {
|
match (&info[0], &info[1]) {
|
||||||
(&ASN1Block::Integer(_,_,ref rint),
|
(&ASN1Block::Integer(_,_,ref rint),
|
||||||
&ASN1Block::Integer(_,_,ref sint)) => {
|
&ASN1Block::Integer(_,_,ref sint)) => {
|
||||||
match (rint.to_biguint(), sint.to_biguint()) {
|
let r = N::from_num(rint).ok_or(DSADecodeError::InvalidRValue)?;
|
||||||
(Some(rnum), Some(snum)) => {
|
let s = N::from_num(sint).ok_or(DSADecodeError::InvalidSValue)?;
|
||||||
let r = N::from_num(rnum).ok_or(DSADecodeError::RValueTooBig)?;
|
Ok((DSASignature{ r, s }, rest))
|
||||||
let s = N::from_num(snum).ok_or(DSADecodeError::SValueTooBig)?;
|
|
||||||
Ok((DSASignature{ r, s }, rest))
|
|
||||||
|
|
||||||
}
|
|
||||||
_ =>
|
|
||||||
Err(DSADecodeError::NegativeSigValues)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => Err(DSADecodeError::NoSignatureFound)
|
_ => Err(DSADecodeError::NoSignatureFound)
|
||||||
}
|
}
|
||||||
@@ -295,15 +288,15 @@ impl<N> FromASN1 for DSASignature<N>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<N> ToASN1 for DSASignature<N>
|
impl<N> ToASN1 for DSASignature<N>
|
||||||
where N: TranslateNums
|
where N: TranslateNums<BigInt>
|
||||||
{
|
{
|
||||||
type Error = ASN1EncodeErr;
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
fn to_asn1_class(&self, c: ASN1Class)
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
{
|
{
|
||||||
let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.to_num()));
|
let rb = ASN1Block::Integer(c, 0, self.r.to_num());
|
||||||
let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.to_num()));
|
let sb = ASN1Block::Integer(c, 0, self.s.to_num());
|
||||||
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
|
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
|
use cryptonum::unsigned::*;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
use simple_asn1::{der_decode,der_encode};
|
use simple_asn1::{der_decode,der_encode};
|
||||||
use super::*;
|
use dsa::params::{DSAParameters,L1024N160,L2048N256};
|
||||||
|
use dsa::private::{DSAPrivateKey,DSAPrivKey};
|
||||||
|
use dsa::public::{DSAPublicKey,DSAPubKey};
|
||||||
use dsa::rfc6979::KIterator;
|
use dsa::rfc6979::KIterator;
|
||||||
|
|
||||||
macro_rules! run_rfc6979_test {
|
macro_rules! run_rfc6979_test {
|
||||||
($hash: ty, $ntype: ident, $val: ident, $public: ident, $private: ident,
|
($hash: ty, $ntype: ident, $val: ident, $params: ident, $public: ident, $private: ident,
|
||||||
k $k: expr,
|
k $k: expr,
|
||||||
r $r: expr,
|
r $r: expr,
|
||||||
s $s: expr) => ({
|
s $s: expr) => ({
|
||||||
@@ -15,9 +18,7 @@ macro_rules! run_rfc6979_test {
|
|||||||
let sbytes = $s;
|
let sbytes = $s;
|
||||||
let r = $ntype::from_bytes(&rbytes);
|
let r = $ntype::from_bytes(&rbytes);
|
||||||
let s = $ntype::from_bytes(&sbytes);
|
let s = $ntype::from_bytes(&sbytes);
|
||||||
let mut iter = KIterator::<$hash,$ntype>::new(&h1, $public.params.n_bits(),
|
let mut iter = KIterator::<$hash,$ntype>::new(&h1, $params.n_bits(), &$params.q, &$private.x);
|
||||||
&$public.params.q,
|
|
||||||
&$private.x);
|
|
||||||
let mut k1 = iter.next().unwrap().to_bytes().to_vec();
|
let mut k1 = iter.next().unwrap().to_bytes().to_vec();
|
||||||
while k1.len() > $k.len() {
|
while k1.len() > $k.len() {
|
||||||
assert_eq!(k1[0], 0);
|
assert_eq!(k1[0], 0);
|
||||||
@@ -98,7 +99,7 @@ fn appendix_a21() {
|
|||||||
let params = L1024N160::new(p, g, q);
|
let params = L1024N160::new(p, g, q);
|
||||||
let x = U192::from_bytes(&xbytes);
|
let x = U192::from_bytes(&xbytes);
|
||||||
let y = U1024::from_bytes(&ybytes);
|
let y = U1024::from_bytes(&ybytes);
|
||||||
let private = DSAPrivKey::<L1024N160,U192>::new(params.clone(), x);
|
let private = DSAPrivKey::new(params.clone(), x);
|
||||||
let public = DSAPubKey::<L1024N160,U1024>::new(params.clone(), y);
|
let public = DSAPubKey::<L1024N160,U1024>::new(params.clone(), y);
|
||||||
//
|
//
|
||||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||||
@@ -107,7 +108,7 @@ fn appendix_a21() {
|
|||||||
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
|
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
|
||||||
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
||||||
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
||||||
run_rfc6979_test!(Sha1, U192, sample, public, private,
|
run_rfc6979_test!(Sha1, U192, sample, params, public, private,
|
||||||
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
|
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
|
||||||
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
|
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
|
||||||
0x9A, 0xD5, 0xBD, 0x5B],
|
0x9A, 0xD5, 0xBD, 0x5B],
|
||||||
@@ -121,7 +122,7 @@ fn appendix_a21() {
|
|||||||
// k = 562097C06782D60C3037BA7BE104774344687649
|
// k = 562097C06782D60C3037BA7BE104774344687649
|
||||||
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
|
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
|
||||||
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
|
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
|
||||||
run_rfc6979_test!(Sha224, U192, sample, public, private,
|
run_rfc6979_test!(Sha224, U192, sample, params, public, private,
|
||||||
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
|
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
|
||||||
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
|
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
|
||||||
0x44, 0x68, 0x76, 0x49],
|
0x44, 0x68, 0x76, 0x49],
|
||||||
@@ -135,7 +136,7 @@ fn appendix_a21() {
|
|||||||
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
|
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
|
||||||
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
|
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
|
||||||
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
|
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
|
||||||
run_rfc6979_test!(Sha256, U192, sample, public, private,
|
run_rfc6979_test!(Sha256, U192, sample, params, public, private,
|
||||||
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
|
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
|
||||||
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
|
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
|
||||||
0xB3, 0x18, 0xBC, 0xFB],
|
0xB3, 0x18, 0xBC, 0xFB],
|
||||||
@@ -149,7 +150,7 @@ fn appendix_a21() {
|
|||||||
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
|
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
|
||||||
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
|
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
|
||||||
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
|
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
|
||||||
run_rfc6979_test!(Sha384, U192, sample, public, private,
|
run_rfc6979_test!(Sha384, U192, sample, params, public, private,
|
||||||
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
|
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
|
||||||
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
|
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
|
||||||
0x6F, 0xCF, 0xC5, 0x95],
|
0x6F, 0xCF, 0xC5, 0x95],
|
||||||
@@ -163,7 +164,7 @@ fn appendix_a21() {
|
|||||||
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
|
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
|
||||||
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
|
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
|
||||||
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
|
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
|
||||||
run_rfc6979_test!(Sha512, U192, sample, public, private,
|
run_rfc6979_test!(Sha512, U192, sample, params, public, private,
|
||||||
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
|
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
|
||||||
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
|
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
|
||||||
0x28, 0x10, 0x4F, 0x8B],
|
0x28, 0x10, 0x4F, 0x8B],
|
||||||
@@ -177,7 +178,7 @@ fn appendix_a21() {
|
|||||||
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
|
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
|
||||||
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
|
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
|
||||||
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
||||||
run_rfc6979_test!(Sha1, U192, test, public, private,
|
run_rfc6979_test!(Sha1, U192, test, params, public, private,
|
||||||
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
|
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
|
||||||
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
|
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
|
||||||
0x7F, 0x4A, 0x64, 0x33],
|
0x7F, 0x4A, 0x64, 0x33],
|
||||||
@@ -191,7 +192,7 @@ fn appendix_a21() {
|
|||||||
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
|
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
|
||||||
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
|
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
|
||||||
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
|
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
|
||||||
run_rfc6979_test!(Sha224, U192, test, public, private,
|
run_rfc6979_test!(Sha224, U192, test, params, public, private,
|
||||||
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
|
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
|
||||||
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
|
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
|
||||||
0x71, 0xE6, 0x72, 0x97],
|
0x71, 0xE6, 0x72, 0x97],
|
||||||
@@ -205,7 +206,7 @@ fn appendix_a21() {
|
|||||||
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
|
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
|
||||||
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
|
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
|
||||||
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
|
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
|
||||||
run_rfc6979_test!(Sha256, U192, test, public, private,
|
run_rfc6979_test!(Sha256, U192, test, params, public, private,
|
||||||
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
|
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
|
||||||
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
|
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
|
||||||
0x0B, 0x63, 0x0E, 0x1A],
|
0x0B, 0x63, 0x0E, 0x1A],
|
||||||
@@ -219,7 +220,7 @@ fn appendix_a21() {
|
|||||||
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
|
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
|
||||||
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
|
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
|
||||||
// s = 91D0E0F53E22F898D158380676A871A157CDA622
|
// s = 91D0E0F53E22F898D158380676A871A157CDA622
|
||||||
run_rfc6979_test!(Sha384, U192, test, public, private,
|
run_rfc6979_test!(Sha384, U192, test, params, public, private,
|
||||||
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
|
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
|
||||||
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
|
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
|
||||||
0x5F, 0x98, 0xCD, 0x89],
|
0x5F, 0x98, 0xCD, 0x89],
|
||||||
@@ -233,7 +234,7 @@ fn appendix_a21() {
|
|||||||
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
|
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
|
||||||
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
|
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
|
||||||
// s = 7C670C7AD72B6C050C109E1790008097125433E8
|
// s = 7C670C7AD72B6C050C109E1790008097125433E8
|
||||||
run_rfc6979_test!(Sha512, U192, test, public, private,
|
run_rfc6979_test!(Sha512, U192, test, params, public, private,
|
||||||
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
|
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
|
||||||
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
|
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
|
||||||
0x2C, 0x7D, 0xBE, 0x9C],
|
0x2C, 0x7D, 0xBE, 0x9C],
|
||||||
@@ -358,8 +359,8 @@ fn appendix_a22() {
|
|||||||
let params = L2048N256::new(p, g, q);
|
let params = L2048N256::new(p, g, q);
|
||||||
let x = U256::from_bytes(&xbytes);
|
let x = U256::from_bytes(&xbytes);
|
||||||
let y = U2048::from_bytes(&ybytes);
|
let y = U2048::from_bytes(&ybytes);
|
||||||
let private = DSAPrivKey::new(params.clone(), x);
|
let private = DSAPrivKey::<L2048N256,U256>::new(params.clone(), x);
|
||||||
let public = DSAPubKey::new(params.clone(), y);
|
let public = DSAPubKey::<L2048N256,U2048>::new(params.clone(), y);
|
||||||
//
|
//
|
||||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||||
@@ -367,7 +368,7 @@ fn appendix_a22() {
|
|||||||
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
|
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
|
||||||
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
||||||
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
||||||
run_rfc6979_test!(Sha1, U256, sample, public, private,
|
run_rfc6979_test!(Sha1, U256, sample, params, public, private,
|
||||||
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
|
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
|
||||||
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
|
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
|
||||||
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
|
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
|
||||||
@@ -384,7 +385,7 @@ fn appendix_a22() {
|
|||||||
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
|
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
|
||||||
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
|
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
|
||||||
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
|
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
|
||||||
run_rfc6979_test!(Sha224, U256, sample, public, private,
|
run_rfc6979_test!(Sha224, U256, sample, params, public, private,
|
||||||
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
|
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
|
||||||
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
|
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
|
||||||
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
|
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
|
||||||
@@ -401,7 +402,7 @@ fn appendix_a22() {
|
|||||||
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
|
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
|
||||||
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
|
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
|
||||||
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
|
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
|
||||||
run_rfc6979_test!(Sha256, U256, sample, public, private,
|
run_rfc6979_test!(Sha256, U256, sample, params, public, private,
|
||||||
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
|
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
|
||||||
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
|
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
|
||||||
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
|
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
|
||||||
@@ -418,7 +419,7 @@ fn appendix_a22() {
|
|||||||
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
|
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
|
||||||
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
|
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
|
||||||
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
|
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
|
||||||
run_rfc6979_test!(Sha384, U256, sample, public, private,
|
run_rfc6979_test!(Sha384, U256, sample, params, public, private,
|
||||||
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
|
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
|
||||||
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
|
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
|
||||||
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
|
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
|
||||||
@@ -435,7 +436,7 @@ fn appendix_a22() {
|
|||||||
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
|
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
|
||||||
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
|
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
|
||||||
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
|
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
|
||||||
run_rfc6979_test!(Sha512, U256, sample, public, private,
|
run_rfc6979_test!(Sha512, U256, sample, params, public, private,
|
||||||
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
|
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
|
||||||
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
|
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
|
||||||
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
|
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
|
||||||
@@ -452,7 +453,7 @@ fn appendix_a22() {
|
|||||||
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
|
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
|
||||||
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
||||||
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
||||||
run_rfc6979_test!(Sha1, U256, test, public, private,
|
run_rfc6979_test!(Sha1, U256, test, params, public, private,
|
||||||
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
|
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
|
||||||
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
|
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
|
||||||
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
|
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
|
||||||
@@ -469,7 +470,7 @@ fn appendix_a22() {
|
|||||||
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
|
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
|
||||||
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
|
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
|
||||||
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
|
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
|
||||||
run_rfc6979_test!(Sha224, U256, test, public, private,
|
run_rfc6979_test!(Sha224, U256, test, params, public, private,
|
||||||
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
|
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
|
||||||
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
|
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
|
||||||
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
|
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
|
||||||
@@ -486,7 +487,7 @@ fn appendix_a22() {
|
|||||||
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
|
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
|
||||||
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
|
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
|
||||||
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
|
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
|
||||||
run_rfc6979_test!(Sha256, U256, test, public, private,
|
run_rfc6979_test!(Sha256, U256, test, params, public, private,
|
||||||
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
|
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
|
||||||
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
|
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
|
||||||
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
|
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
|
||||||
@@ -503,7 +504,7 @@ fn appendix_a22() {
|
|||||||
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
|
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
|
||||||
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
|
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
|
||||||
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
|
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
|
||||||
run_rfc6979_test!(Sha384, U256, test, public, private,
|
run_rfc6979_test!(Sha384, U256, test, params, public, private,
|
||||||
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
|
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
|
||||||
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
|
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
|
||||||
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
|
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
|
||||||
@@ -520,7 +521,7 @@ fn appendix_a22() {
|
|||||||
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
|
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
|
||||||
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
|
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
|
||||||
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
|
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
|
||||||
run_rfc6979_test!(Sha512, U256, test, public, private,
|
run_rfc6979_test!(Sha512, U256, test, params, public, private,
|
||||||
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
|
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
|
||||||
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
|
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
|
||||||
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,
|
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ use rand::distributions::Standard;
|
|||||||
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||||
use self::point::{ECCPoint,Point};
|
use self::point::{ECCPoint,Point};
|
||||||
pub use self::private::{ECCPrivateKey,ECCPrivate};
|
pub use self::private::{ECCPrivateKey,ECCPrivate};
|
||||||
pub use self::public::{ECCPublicKey,ECCPublic};
|
pub use self::public::{ECCPublicKey,ECDSAPublic,ECCPubKey};
|
||||||
|
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
|
||||||
|
|
||||||
pub trait ECDSAKeyPair<Public,Private> {
|
pub trait ECDSAKeyPair<Public,Private> {
|
||||||
fn generate<G: Rng>(g: &mut G) -> (Public, Private);
|
fn generate<G: Rng>(g: &mut G) -> (Public, Private);
|
||||||
@@ -19,8 +20,8 @@ pub trait ECDSAKeyPair<Public,Private> {
|
|||||||
|
|
||||||
macro_rules! generate_impl {
|
macro_rules! generate_impl {
|
||||||
($curve: ident, $un: ident, $si: ident) => {
|
($curve: ident, $un: ident, $si: ident) => {
|
||||||
impl ECDSAKeyPair<ECCPublic<$curve>,ECCPrivate<$curve>> for $curve {
|
impl ECDSAKeyPair<ECCPubKey<$curve>,ECCPrivate<$curve>> for $curve {
|
||||||
fn generate<G: Rng>(rng: &mut G) -> (ECCPublic<$curve>, ECCPrivate<$curve>)
|
fn generate<G: Rng>(rng: &mut G) -> (ECCPubKey<$curve>, ECCPrivate<$curve>)
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
let size = ($curve::size() + 7) / 8;
|
let size = ($curve::size() + 7) / 8;
|
||||||
@@ -37,7 +38,7 @@ macro_rules! generate_impl {
|
|||||||
|
|
||||||
let d = $si::from(&proposed_d);
|
let d = $si::from(&proposed_d);
|
||||||
let public_point = Point::<$curve>::default().scale(&d);
|
let public_point = Point::<$curve>::default().scale(&d);
|
||||||
let public = ECCPublic::<$curve>::new(public_point);
|
let public = ECCPubKey::<$curve>::new(public_point);
|
||||||
let private = ECCPrivate::<$curve>::new(proposed_d);
|
let private = ECCPrivate::<$curve>::new(proposed_d);
|
||||||
return (public, private);
|
return (public, private);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,36 +5,70 @@ use dsa::rfc6979::DSASignature;
|
|||||||
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||||
use ecdsa::point::{ECCPoint,Point};
|
use ecdsa::point::{ECCPoint,Point};
|
||||||
use hmac::{Hmac,Mac};
|
use hmac::{Hmac,Mac};
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
pub struct ECCPublic<Curve: EllipticCurve> {
|
pub struct ECCPubKey<Curve: EllipticCurve> {
|
||||||
q: Point<Curve>
|
q: Point<Curve>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ECDSAPublic {
|
||||||
|
ECCPublicP192(ECCPubKey<P192>),
|
||||||
|
ECCPublicP224(ECCPubKey<P224>),
|
||||||
|
ECCPublicP256(ECCPubKey<P256>),
|
||||||
|
ECCPublicP384(ECCPubKey<P384>),
|
||||||
|
ECCPublicP521(ECCPubKey<P521>),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ECCPublicKey {
|
pub trait ECCPublicKey {
|
||||||
type Curve : EllipticCurve;
|
type Curve : EllipticCurve;
|
||||||
type Unsigned;
|
type Unsigned;
|
||||||
|
|
||||||
fn new(d: Point<Self::Curve>) -> Self;
|
fn new(d: Point<Self::Curve>) -> Self;
|
||||||
fn verify<Hash>(&self, m: &[u8], sig: DSASignature<Self::Unsigned>) -> bool
|
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
|
||||||
where
|
where
|
||||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||||
Hmac<Hash>: Mac;
|
Hmac<Hash>: Mac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ECDSAEncodeErr {
|
||||||
|
ASN1EncodeErr(ASN1EncodeErr),
|
||||||
|
XValueNegative, YValueNegative
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1EncodeErr> for ECDSAEncodeErr {
|
||||||
|
fn from(x: ASN1EncodeErr) -> ECDSAEncodeErr {
|
||||||
|
ECDSAEncodeErr::ASN1EncodeErr(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ECDSADecodeErr {
|
||||||
|
ASN1DecodeErr(ASN1DecodeErr),
|
||||||
|
NoKeyFound,
|
||||||
|
InvalidKeyFormat,
|
||||||
|
InvalidKeyBlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1DecodeErr> for ECDSADecodeErr {
|
||||||
|
fn from(x: ASN1DecodeErr) -> ECDSADecodeErr {
|
||||||
|
ECDSADecodeErr::ASN1DecodeErr(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! public_impl {
|
macro_rules! public_impl {
|
||||||
($curve: ident, $un: ident, $si: ident) => {
|
($curve: ident, $un: ident, $si: ident) => {
|
||||||
impl ECCPublicKey for ECCPublic<$curve>
|
impl ECCPublicKey for ECCPubKey<$curve>
|
||||||
{
|
{
|
||||||
type Curve = $curve;
|
type Curve = $curve;
|
||||||
type Unsigned = $un;
|
type Unsigned = $un;
|
||||||
|
|
||||||
fn new(q: Point<$curve>) -> ECCPublic<$curve>
|
fn new(q: Point<$curve>) -> ECCPubKey<$curve>
|
||||||
{
|
{
|
||||||
ECCPublic{ q }
|
ECCPubKey{ q }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify<Hash>(&self, m: &[u8], sig: DSASignature<Self::Unsigned>) -> bool
|
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
|
||||||
where
|
where
|
||||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||||
Hmac<Hash>: Mac
|
Hmac<Hash>: Mac
|
||||||
@@ -68,6 +102,66 @@ macro_rules! public_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for ECCPubKey<$curve> {
|
||||||
|
type Error = ECDSAEncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
|
||||||
|
{
|
||||||
|
if self.q.x.is_negative() {
|
||||||
|
return Err(ECDSAEncodeErr::XValueNegative);
|
||||||
|
}
|
||||||
|
if self.q.y.is_negative() {
|
||||||
|
return Err(ECDSAEncodeErr::YValueNegative);
|
||||||
|
}
|
||||||
|
|
||||||
|
let xval = $un::from(&self.q.x);
|
||||||
|
let yval = $un::from(&self.q.y);
|
||||||
|
let mut xbytes = xval.to_bytes();
|
||||||
|
let mut ybytes = yval.to_bytes();
|
||||||
|
let goalsize = ($curve::size() + 7) / 8;
|
||||||
|
let mut target = Vec::with_capacity(1 + (goalsize * 2));
|
||||||
|
|
||||||
|
while xbytes.len() > goalsize { xbytes.remove(0); };
|
||||||
|
while xbytes.len() < goalsize { xbytes.insert(0,0) };
|
||||||
|
while ybytes.len() > goalsize { ybytes.remove(0); };
|
||||||
|
while ybytes.len() < goalsize { ybytes.insert(0,0) };
|
||||||
|
|
||||||
|
target.push(4);
|
||||||
|
target.append(&mut xbytes);
|
||||||
|
target.append(&mut ybytes);
|
||||||
|
|
||||||
|
let result = ASN1Block::BitString(c, 0, target.len() * 8, target);
|
||||||
|
Ok(vec![result])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for ECCPubKey<$curve> {
|
||||||
|
type Error = ECDSADecodeErr;
|
||||||
|
|
||||||
|
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPubKey<$curve>,&[ASN1Block]),ECDSADecodeErr>
|
||||||
|
{
|
||||||
|
let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?;
|
||||||
|
if let ASN1Block::BitString(_, _, _, target) = x {
|
||||||
|
let (hdr, xy_bstr) = target.split_first().ok_or(ECDSADecodeErr::InvalidKeyFormat)?;
|
||||||
|
if *hdr != 4 {
|
||||||
|
return Err(ECDSADecodeErr::InvalidKeyFormat);
|
||||||
|
}
|
||||||
|
let goalsize = ($curve::size() + 7) / 8;
|
||||||
|
if xy_bstr.len() != (2 * goalsize) {
|
||||||
|
return Err(ECDSADecodeErr::InvalidKeyBlockSize);
|
||||||
|
}
|
||||||
|
let (xbstr, ybstr) = xy_bstr.split_at(goalsize);
|
||||||
|
let x = $un::from_bytes(xbstr);
|
||||||
|
let y = $un::from_bytes(ybstr);
|
||||||
|
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||||
|
let res = ECCPubKey::<$curve>::new(point);
|
||||||
|
Ok((res, rest))
|
||||||
|
} else {
|
||||||
|
Err(ECDSADecodeErr::InvalidKeyFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,13 +201,13 @@ macro_rules! test_impl {
|
|||||||
let s = $un::from_bytes(sbytes);
|
let s = $un::from_bytes(sbytes);
|
||||||
|
|
||||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||||
let public = ECCPublic::<$curve>::new(point);
|
let public = ECCPubKey::<$curve>::new(point);
|
||||||
let sig = DSASignature::new(r, s);
|
let sig = DSASignature::new(r, s);
|
||||||
match usize::from(h) {
|
match usize::from(h) {
|
||||||
224 => assert!(public.verify::<Sha224>(mbytes, sig)),
|
224 => assert!(public.verify::<Sha224>(mbytes, &sig)),
|
||||||
256 => assert!(public.verify::<Sha256>(mbytes, sig)),
|
256 => assert!(public.verify::<Sha256>(mbytes, &sig)),
|
||||||
384 => assert!(public.verify::<Sha384>(mbytes, sig)),
|
384 => assert!(public.verify::<Sha384>(mbytes, &sig)),
|
||||||
512 => assert!(public.verify::<Sha512>(mbytes, sig)),
|
512 => assert!(public.verify::<Sha512>(mbytes, &sig)),
|
||||||
x => panic!("Unknown hash algorithm {}", x)
|
x => panic!("Unknown hash algorithm {}", x)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//! when they should use it, and examples. For now, it mostly just fowards
|
//! when they should use it, and examples. For now, it mostly just fowards
|
||||||
//! off to more detailed modules. Help requested!
|
//! off to more detailed modules. Help requested!
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
extern crate chrono;
|
||||||
extern crate cryptonum;
|
extern crate cryptonum;
|
||||||
extern crate digest;
|
extern crate digest;
|
||||||
extern crate hmac;
|
extern crate hmac;
|
||||||
@@ -20,6 +21,7 @@ extern crate quickcheck;
|
|||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate sha1;
|
extern crate sha1;
|
||||||
extern crate sha2;
|
extern crate sha2;
|
||||||
|
#[macro_use]
|
||||||
extern crate simple_asn1;
|
extern crate simple_asn1;
|
||||||
|
|
||||||
/// The `rsa` module provides bare-bones support for RSA signing, verification,
|
/// The `rsa` module provides bare-bones support for RSA signing, verification,
|
||||||
@@ -33,6 +35,9 @@ pub mod dsa;
|
|||||||
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
||||||
/// verification, and key generation.
|
/// verification, and key generation.
|
||||||
pub mod ecdsa;
|
pub mod ecdsa;
|
||||||
|
/// The `x509` module supports parsing and generating x.509 certificates, as
|
||||||
|
/// used by TLS and others.
|
||||||
|
pub mod x509;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod testing;
|
mod testing;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ mod private;
|
|||||||
mod public;
|
mod public;
|
||||||
mod signing_hashes;
|
mod signing_hashes;
|
||||||
|
|
||||||
|
pub use self::errors::RSAError;
|
||||||
pub use self::signing_hashes::{SigningHash,
|
pub use self::signing_hashes::{SigningHash,
|
||||||
SIGNING_HASH_NULL,
|
SIGNING_HASH_NULL,
|
||||||
SIGNING_HASH_SHA1,
|
SIGNING_HASH_SHA1,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use digest::{Digest,FixedOutput};
|
use digest::{Digest,FixedOutput};
|
||||||
use num::BigInt;
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
|
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
|
||||||
@@ -71,6 +70,21 @@ pub enum RSAPublic {
|
|||||||
Key15360(RSA15360Public)
|
Key15360(RSA15360Public)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RSAPublic {
|
||||||
|
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
RSAPublic::Key512(x) => x.verify(signhash, msg, sig),
|
||||||
|
RSAPublic::Key1024(x) => x.verify(signhash, msg, sig),
|
||||||
|
RSAPublic::Key2048(x) => x.verify(signhash, msg, sig),
|
||||||
|
RSAPublic::Key3072(x) => x.verify(signhash, msg, sig),
|
||||||
|
RSAPublic::Key4096(x) => x.verify(signhash, msg, sig),
|
||||||
|
RSAPublic::Key8192(x) => x.verify(signhash, msg, sig),
|
||||||
|
RSAPublic::Key15360(x) => x.verify(signhash, msg, sig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromASN1 for RSAPublic {
|
impl FromASN1 for RSAPublic {
|
||||||
type Error = RSAError;
|
type Error = RSAError;
|
||||||
|
|
||||||
@@ -95,44 +109,44 @@ impl FromASN1 for RSAPublic {
|
|||||||
}
|
}
|
||||||
match rsa_size {
|
match rsa_size {
|
||||||
512 => {
|
512 => {
|
||||||
let n2 = U512::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U512::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA512Public::new(n2, e2);
|
let res = RSA512Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key512(res), rest))
|
Ok((RSAPublic::Key512(res), rest))
|
||||||
}
|
}
|
||||||
1024 => {
|
1024 => {
|
||||||
let n2 = U1024::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U1024::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA1024Public::new(n2, e2);
|
let res = RSA1024Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key1024(res), rest))
|
Ok((RSAPublic::Key1024(res), rest))
|
||||||
}
|
}
|
||||||
2048 => {
|
2048 => {
|
||||||
let n2 = U2048::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U2048::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA2048Public::new(n2, e2);
|
let res = RSA2048Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key2048(res), rest))
|
Ok((RSAPublic::Key2048(res), rest))
|
||||||
}
|
}
|
||||||
3072 => {
|
3072 => {
|
||||||
let n2 = U3072::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U3072::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA3072Public::new(n2, e2);
|
let res = RSA3072Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key3072(res), rest))
|
Ok((RSAPublic::Key3072(res), rest))
|
||||||
}
|
}
|
||||||
4096 => {
|
4096 => {
|
||||||
let n2 = U4096::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U4096::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA4096Public::new(n2, e2);
|
let res = RSA4096Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key4096(res), rest))
|
Ok((RSAPublic::Key4096(res), rest))
|
||||||
}
|
}
|
||||||
8192 => {
|
8192 => {
|
||||||
let n2 = U8192::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U8192::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA8192Public::new(n2, e2);
|
let res = RSA8192Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key8192(res), rest))
|
Ok((RSAPublic::Key8192(res), rest))
|
||||||
}
|
}
|
||||||
15360 => {
|
15360 => {
|
||||||
let n2 = U15360::from_num(n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U15360::from_num(e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA15360Public::new(n2, e2);
|
let res = RSA15360Public::new(n2, e2);
|
||||||
Ok((RSAPublic::Key15360(res), rest))
|
Ok((RSAPublic::Key15360(res), rest))
|
||||||
}
|
}
|
||||||
@@ -301,8 +315,8 @@ macro_rules! generate_rsa_public
|
|||||||
fn to_asn1_class(&self, c: ASN1Class)
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
-> Result<Vec<ASN1Block>,Self::Error>
|
-> Result<Vec<ASN1Block>,Self::Error>
|
||||||
{
|
{
|
||||||
let n = BigInt::from(self.n.to_num());
|
let n = self.n.to_num();
|
||||||
let e = BigInt::from(self.e.to_num());
|
let e = self.e.to_num();
|
||||||
let enc_n = ASN1Block::Integer(c, 0, n);
|
let enc_n = ASN1Block::Integer(c, 0, n);
|
||||||
let enc_e = ASN1Block::Integer(c, 0, e);
|
let enc_e = ASN1Block::Integer(c, 0, e);
|
||||||
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
|
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
|
||||||
|
|||||||
28
src/utils.rs
28
src/utils.rs
@@ -1,15 +1,16 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use num::BigUint;
|
use num::{BigInt,BigUint};
|
||||||
|
use num::bigint::Sign;
|
||||||
|
|
||||||
pub trait TranslateNums: Sized {
|
pub trait TranslateNums<N>: Sized {
|
||||||
fn from_num(x: BigUint) -> Option<Self>;
|
fn from_num(x: &N) -> Option<Self>;
|
||||||
fn to_num(&self) -> BigUint;
|
fn to_num(&self) -> N;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! from_biguint {
|
macro_rules! from_biguint {
|
||||||
($uname: ident, $size: expr) => {
|
($uname: ident, $size: expr) => {
|
||||||
impl TranslateNums for $uname {
|
impl TranslateNums<BigUint> for $uname {
|
||||||
fn from_num(x: BigUint) -> Option<$uname> {
|
fn from_num(x: &BigUint) -> Option<$uname> {
|
||||||
let mut base_vec = x.to_bytes_be();
|
let mut base_vec = x.to_bytes_be();
|
||||||
let target_bytes = $size / 8;
|
let target_bytes = $size / 8;
|
||||||
|
|
||||||
@@ -29,15 +30,28 @@ macro_rules! from_biguint {
|
|||||||
BigUint::from_bytes_be(&bytes)
|
BigUint::from_bytes_be(&bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TranslateNums<BigInt> for $uname {
|
||||||
|
fn from_num(x: &BigInt) -> Option<$uname> {
|
||||||
|
let ux = x.to_biguint()?;
|
||||||
|
$uname::from_num(&ux)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_num(&self) -> BigInt {
|
||||||
|
BigInt::from_biguint(Sign::Plus, self.to_num())
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
from_biguint!(U192, 192);
|
from_biguint!(U192, 192);
|
||||||
from_biguint!(U256, 256);
|
from_biguint!(U256, 256);
|
||||||
|
from_biguint!(U384, 384);
|
||||||
from_biguint!(U512, 512);
|
from_biguint!(U512, 512);
|
||||||
|
from_biguint!(U576, 576);
|
||||||
from_biguint!(U1024, 1024);
|
from_biguint!(U1024, 1024);
|
||||||
from_biguint!(U2048, 2048);
|
from_biguint!(U2048, 2048);
|
||||||
from_biguint!(U3072, 3072);
|
from_biguint!(U3072, 3072);
|
||||||
from_biguint!(U4096, 4096);
|
from_biguint!(U4096, 4096);
|
||||||
from_biguint!(U8192, 8192);
|
from_biguint!(U8192, 8192);
|
||||||
from_biguint!(U15360, 15360);
|
from_biguint!(U15360, 15360);
|
||||||
377
src/x509/algident.rs
Normal file
377
src/x509/algident.rs
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
use num::BigUint;
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
|
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
||||||
|
|
||||||
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
|
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct AlgorithmIdentifier {
|
||||||
|
pub hash: HashAlgorithm,
|
||||||
|
pub algo: PublicKeyInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for AlgorithmIdentifier {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(AlgorithmIdentifier,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match v.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NotEnoughData),
|
||||||
|
Some((x, rest)) => {
|
||||||
|
let v = decode_algorithm_ident(&x)?;
|
||||||
|
Ok((v, rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_algorithm_ident(x: &ASN1Block)
|
||||||
|
-> Result<AlgorithmIdentifier,X509ParseError>
|
||||||
|
{
|
||||||
|
// AlgorithmIdentifier ::= SEQUENCE {
|
||||||
|
// algorithm OBJECT IDENTIFIER,
|
||||||
|
// parameters ANY DEFINED BY algorithm OPTIONAL }
|
||||||
|
match x {
|
||||||
|
&ASN1Block::Sequence(_, _, ref v) if v.len() >= 1 => {
|
||||||
|
match v[0] {
|
||||||
|
ASN1Block::ObjectIdentifier(_, _, ref oid) => {
|
||||||
|
if oid == oid!(1,2,840,113549,1,1,5) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA1,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,113549,1,1,11) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA256,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,113549,1,1,12) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA384,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,113549,1,1,13) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA512,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,113549,1,1,14) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA224,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,10040,4,3) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA1,
|
||||||
|
algo: PublicKeyInfo::DSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,10045,4,1) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA1,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,10045,4,3,1) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA224,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,10045,4,3,2) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA256,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,10045,4,3,3) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA384,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,10045,4,3,4) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA512,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// if oid == oid!(2,16,840,1,101,3,4,2,1) {
|
||||||
|
// return Ok(AlgorithmIdentifier {
|
||||||
|
// hash: HashAlgorithm::SHA256,
|
||||||
|
// algo: PublicKeyInfo::RSAPSS
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// if oid == oid!(2,16,840,1,101,3,4,2,2) {
|
||||||
|
// return Ok(AlgorithmIdentifier {
|
||||||
|
// hash: HashAlgorithm::SHA384,
|
||||||
|
// algo: PublicKeyInfo::RSAPSS
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// if oid == oid!(2,16,840,1,101,3,4,2,3) {
|
||||||
|
// return Ok(AlgorithmIdentifier {
|
||||||
|
// hash: HashAlgorithm::SHA512,
|
||||||
|
// algo: PublicKeyInfo::RSAPSS
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// if oid == oid!(2,16,840,1,101,3,4,2,4) {
|
||||||
|
// return Ok(AlgorithmIdentifier {
|
||||||
|
// hash: HashAlgorithm::SHA224,
|
||||||
|
// algo: PublicKeyInfo::RSAPSS
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
if oid == oid!(2,16,840,1,101,3,4,3,1) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA224,
|
||||||
|
algo: PublicKeyInfo::DSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if oid == oid!(2,16,840,1,101,3,4,3,2) {
|
||||||
|
return Ok(AlgorithmIdentifier {
|
||||||
|
hash: HashAlgorithm::SHA256,
|
||||||
|
algo: PublicKeyInfo::DSA
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(X509ParseError::UnknownAlgorithm)
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::UnknownAlgorithm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedAlgoInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub enum SigAlgEncodeError {
|
||||||
|
ASN1Error(ASN1EncodeErr),
|
||||||
|
InvalidDSAValue, InvalidHash
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1EncodeErr> for SigAlgEncodeError {
|
||||||
|
fn from(e: ASN1EncodeErr) -> SigAlgEncodeError {
|
||||||
|
SigAlgEncodeError::ASN1Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ToASN1 for AlgorithmIdentifier {
|
||||||
|
type Error = SigAlgEncodeError;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,SigAlgEncodeError>
|
||||||
|
{
|
||||||
|
let block = encode_algorithm_ident(c, self)?;
|
||||||
|
Ok(vec![block])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_algorithm_ident(c: ASN1Class, x: &AlgorithmIdentifier)
|
||||||
|
-> Result<ASN1Block,SigAlgEncodeError>
|
||||||
|
{
|
||||||
|
match x.algo {
|
||||||
|
PublicKeyInfo::RSA => {
|
||||||
|
match x.hash {
|
||||||
|
HashAlgorithm::SHA1 => {
|
||||||
|
let o = oid!(1,2,840,113549,1,1,5);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA224 => {
|
||||||
|
let o = oid!(1,2,840,113549,1,1,14);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA256 => {
|
||||||
|
let o = oid!(1,2,840,113549,1,1,11);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA384 => {
|
||||||
|
let o = oid!(1,2,840,113549,1,1,12);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA512 => {
|
||||||
|
let o = oid!(1,2,840,113549,1,1,13);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PublicKeyInfo::DSA => {
|
||||||
|
match x.hash {
|
||||||
|
HashAlgorithm::SHA1 => {
|
||||||
|
let o = oid!(1,2,840,10040,4,3);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA224 => {
|
||||||
|
let o = oid!(2,16,840,1,101,3,4,3,1);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA256 => {
|
||||||
|
let o = oid!(2,16,840,1,101,3,4,3,2);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(SigAlgEncodeError::InvalidHash),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PublicKeyInfo::ECDSA=> {
|
||||||
|
match x.hash {
|
||||||
|
HashAlgorithm::SHA1 => {
|
||||||
|
let o = oid!(1,2,840,10045,4,1);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA224 => {
|
||||||
|
let o = oid!(1,2,840,10045,4,3,1);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA256 => {
|
||||||
|
let o = oid!(1,2,840,10045,4,3,2);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA384 => {
|
||||||
|
let o = oid!(1,2,840,10045,4,3,3);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
HashAlgorithm::SHA512 => {
|
||||||
|
let o = oid!(1,2,840,10045,4,3,4);
|
||||||
|
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use rand::prelude::SliceRandom;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const RSA1: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA1,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const RSA224: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA224,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const RSA256: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA256,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const RSA384: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA384,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const RSA512: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA512,
|
||||||
|
algo: PublicKeyInfo::RSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const DSA1: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA1,
|
||||||
|
algo: PublicKeyInfo::DSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const DSA224: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA224,
|
||||||
|
algo: PublicKeyInfo::DSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const DSA256: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA256,
|
||||||
|
algo: PublicKeyInfo::DSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const EC1: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA1,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const EC224: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA224,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const EC256: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA256,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const EC384: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA384,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
};
|
||||||
|
|
||||||
|
const EC512: AlgorithmIdentifier =
|
||||||
|
AlgorithmIdentifier{
|
||||||
|
hash: HashAlgorithm::SHA512,
|
||||||
|
algo: PublicKeyInfo::ECDSA
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Arbitrary for AlgorithmIdentifier {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> AlgorithmIdentifier {
|
||||||
|
let opts = [RSA1, RSA224, RSA256, RSA384, RSA512,
|
||||||
|
DSA1, DSA224, DSA256,
|
||||||
|
EC1, EC224, EC256, EC384, EC512];
|
||||||
|
opts.choose(g).unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck!{
|
||||||
|
fn algident_roundtrips(v: AlgorithmIdentifier) -> bool {
|
||||||
|
match encode_algorithm_ident(ASN1Class::Universal, &v) {
|
||||||
|
Err(_) =>
|
||||||
|
false,
|
||||||
|
Ok(block) => {
|
||||||
|
match decode_algorithm_ident(&block) {
|
||||||
|
Err(_) =>
|
||||||
|
false,
|
||||||
|
Ok(v2) =>
|
||||||
|
v == v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
368
src/x509/atv.rs
Normal file
368
src/x509/atv.rs
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
|
use std::ops::Index;
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
use x509::name::X520Name;
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
|
pub struct InfoBlock {
|
||||||
|
fields: Vec<AttributeTypeValue>
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY_STRING: &'static str = "";
|
||||||
|
|
||||||
|
impl Index<X520Name> for InfoBlock {
|
||||||
|
type Output = str;
|
||||||
|
|
||||||
|
fn index(&self, name: X520Name) -> &str {
|
||||||
|
for atv in self.fields.iter() {
|
||||||
|
if name == atv.attrtype {
|
||||||
|
return &atv.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&EMPTY_STRING
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for InfoBlock {
|
||||||
|
fn eq(&self, other: &InfoBlock) -> bool {
|
||||||
|
for x in self.fields.iter() {
|
||||||
|
if !other.fields.contains(x) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for x in other.fields.iter() {
|
||||||
|
if !self.fields.contains(x) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_info_block(x: &ASN1Block)
|
||||||
|
-> Result<InfoBlock,X509ParseError>
|
||||||
|
{
|
||||||
|
// Name ::= CHOICE { -- only one possibility for now --
|
||||||
|
// rdnSequence RDNSequence }
|
||||||
|
//
|
||||||
|
// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
|
||||||
|
//
|
||||||
|
// RelativeDistinguishedName ::=
|
||||||
|
// SET SIZE (1..MAX) OF AttributeTypeAndValue
|
||||||
|
match x {
|
||||||
|
&ASN1Block::Sequence(_, _, ref items) => {
|
||||||
|
let mut atvs = Vec::new();
|
||||||
|
|
||||||
|
for set in items.iter() {
|
||||||
|
match set {
|
||||||
|
&ASN1Block::Set(_, _, ref setitems) => {
|
||||||
|
for atv in setitems.iter() {
|
||||||
|
let v = decode_attribute_type_value(atv)?;
|
||||||
|
atvs.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
return Err(X509ParseError::IllFormedInfoBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(InfoBlock{ fields: atvs })
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedInfoBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for InfoBlock {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(InfoBlock,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match v.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NotEnoughData),
|
||||||
|
Some((x, rest)) => {
|
||||||
|
let v = decode_info_block(&x)?;
|
||||||
|
Ok((v, rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_info_block(c: ASN1Class, b: &InfoBlock)
|
||||||
|
-> Result<ASN1Block,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let mut encoded_fields = Vec::with_capacity(b.fields.len());
|
||||||
|
|
||||||
|
for fld in b.fields.iter() {
|
||||||
|
let val = encode_attribute_type_value(c, fld)?;
|
||||||
|
encoded_fields.push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
let set = ASN1Block::Set(c, 0, encoded_fields);
|
||||||
|
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![set]))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for InfoBlock {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let block = encode_info_block(c, self)?;
|
||||||
|
Ok(vec![block])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
struct AttributeTypeValue {
|
||||||
|
attrtype: X520Name,
|
||||||
|
value: String
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_attribute_type_value(x: &ASN1Block)
|
||||||
|
-> Result<AttributeTypeValue,X509ParseError>
|
||||||
|
{
|
||||||
|
// AttributeTypeAndValue ::= SEQUENCE {
|
||||||
|
// type AttributeType,
|
||||||
|
// value AttributeValue }
|
||||||
|
match x {
|
||||||
|
&ASN1Block::Sequence(_, _, ref xs) => {
|
||||||
|
let (name, rest) = X520Name::from_asn1(xs)?;
|
||||||
|
match rest.first() {
|
||||||
|
None => Err(X509ParseError::NotEnoughData),
|
||||||
|
Some(ref x) => {
|
||||||
|
let atvstr = get_atv_string(name, x)?;
|
||||||
|
Ok(AttributeTypeValue{
|
||||||
|
attrtype: name,
|
||||||
|
value: atvstr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedAttrTypeValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for AttributeTypeValue {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(AttributeTypeValue,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match v.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NotEnoughData),
|
||||||
|
Some((x, rest)) => {
|
||||||
|
let v = decode_attribute_type_value(&x)?;
|
||||||
|
Ok((v, rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_attribute_type_value(c: ASN1Class, x: &AttributeTypeValue)
|
||||||
|
-> Result<ASN1Block,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let mut resvec = x.attrtype.to_asn1_class(c)?;
|
||||||
|
let value = match x.attrtype {
|
||||||
|
X520Name::CountryName =>
|
||||||
|
ASN1Block::PrintableString(c,0,x.value.clone()),
|
||||||
|
X520Name::SerialNumber =>
|
||||||
|
ASN1Block::PrintableString(c,0,x.value.clone()),
|
||||||
|
X520Name::DomainComponent =>
|
||||||
|
ASN1Block::IA5String(c,0,x.value.clone()),
|
||||||
|
X520Name::EmailAddress =>
|
||||||
|
ASN1Block::IA5String(c,0,x.value.clone()),
|
||||||
|
_ =>
|
||||||
|
ASN1Block::UTF8String(c,0,x.value.clone())
|
||||||
|
};
|
||||||
|
resvec.push(value);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, resvec))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for AttributeTypeValue {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let block = encode_attribute_type_value(c, self)?;
|
||||||
|
Ok(vec![block])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_atv_string(n: X520Name, x: &ASN1Block)
|
||||||
|
-> Result<String,X509ParseError>
|
||||||
|
{
|
||||||
|
match n {
|
||||||
|
X520Name::CountryName => {
|
||||||
|
let res = get_printable_val(x)?;
|
||||||
|
if res.len() != 2 {
|
||||||
|
return Err(X509ParseError::IllegalStringValue);
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
X520Name::SerialNumber => get_printable_val(x),
|
||||||
|
X520Name::DomainComponent => get_ia5_val(x),
|
||||||
|
X520Name::EmailAddress => get_ia5_val(x),
|
||||||
|
_ => get_string_val(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_string_val(a: &ASN1Block) -> Result<String,X509ParseError>
|
||||||
|
{
|
||||||
|
match a {
|
||||||
|
&ASN1Block::TeletexString(_,_,ref v) => Ok(v.clone()),
|
||||||
|
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
|
||||||
|
&ASN1Block::UniversalString(_,_,ref v) => Ok(v.clone()),
|
||||||
|
&ASN1Block::UTF8String(_,_,ref v) => Ok(v.clone()),
|
||||||
|
&ASN1Block::BMPString(_,_,ref v) => Ok(v.clone()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllegalStringValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_printable_val(a: &ASN1Block) -> Result<String,X509ParseError>
|
||||||
|
{
|
||||||
|
match a {
|
||||||
|
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllegalStringValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ia5_val(a: &ASN1Block) -> Result<String,X509ParseError>
|
||||||
|
{
|
||||||
|
match a {
|
||||||
|
&ASN1Block::IA5String(_,_,ref v) => Ok(v.clone()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllegalStringValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::prelude::SliceRandom;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Arbitrary for X520Name {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> X520Name {
|
||||||
|
let names = vec![X520Name::Name,
|
||||||
|
X520Name::Surname,
|
||||||
|
X520Name::GivenName,
|
||||||
|
X520Name::Initials,
|
||||||
|
X520Name::GenerationQualifier,
|
||||||
|
X520Name::CommonName,
|
||||||
|
X520Name::LocalityName,
|
||||||
|
X520Name::StateOrProvinceName,
|
||||||
|
X520Name::OrganizationName,
|
||||||
|
X520Name::OrganizationalUnit,
|
||||||
|
X520Name::Title,
|
||||||
|
X520Name::DNQualifier,
|
||||||
|
X520Name::CountryName,
|
||||||
|
X520Name::SerialNumber,
|
||||||
|
X520Name::Pseudonym,
|
||||||
|
X520Name::DomainComponent,
|
||||||
|
X520Name::EmailAddress];
|
||||||
|
names.choose(g).unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arbitrary for AttributeTypeValue {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> AttributeTypeValue {
|
||||||
|
let name = X520Name::arbitrary(g);
|
||||||
|
let val = match name {
|
||||||
|
X520Name::CountryName => {
|
||||||
|
let mut base = gen_printable(g);
|
||||||
|
base.push('U');
|
||||||
|
base.push('S');
|
||||||
|
base.truncate(2);
|
||||||
|
base
|
||||||
|
}
|
||||||
|
X520Name::SerialNumber => gen_printable(g),
|
||||||
|
X520Name::DomainComponent => gen_ia5(g),
|
||||||
|
X520Name::EmailAddress => gen_ia5(g),
|
||||||
|
_ => gen_utf8(g)
|
||||||
|
};
|
||||||
|
AttributeTypeValue{ attrtype: name, value: val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRINTABLE_CHARS: &'static str =
|
||||||
|
"ABCDEFGHIJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? ";
|
||||||
|
|
||||||
|
fn gen_printable<G: Gen>(g: &mut G) -> String {
|
||||||
|
let count = g.gen_range(0, 384);
|
||||||
|
let mut items = Vec::with_capacity(count);
|
||||||
|
|
||||||
|
for _ in 0..count {
|
||||||
|
let v = PRINTABLE_CHARS.as_bytes().choose(g).unwrap();
|
||||||
|
items.push(*v as char);
|
||||||
|
}
|
||||||
|
String::from_iter(items.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_ia5<G: Gen>(g: &mut G) -> String {
|
||||||
|
let count = g.gen_range(0, 384);
|
||||||
|
let mut items = Vec::with_capacity(count);
|
||||||
|
|
||||||
|
for _ in 0..count {
|
||||||
|
items.push(g.gen::<u8>() as char);
|
||||||
|
}
|
||||||
|
String::from_iter(items.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_utf8<G: Gen>(g: &mut G) -> String {
|
||||||
|
String::arbitrary(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arbitrary for InfoBlock {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> InfoBlock {
|
||||||
|
let count = g.gen_range(0,12);
|
||||||
|
let mut items = Vec::with_capacity(count);
|
||||||
|
let mut names = Vec::with_capacity(count);
|
||||||
|
|
||||||
|
while items.len() < count {
|
||||||
|
let atv = AttributeTypeValue::arbitrary(g);
|
||||||
|
if !names.contains(&atv.attrtype) {
|
||||||
|
names.push(atv.attrtype);
|
||||||
|
items.push(atv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoBlock{ fields: items }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn attrtypeval_roundtrips(v: AttributeTypeValue) -> bool {
|
||||||
|
match encode_attribute_type_value(ASN1Class::Universal, &v) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(bstr) =>
|
||||||
|
match decode_attribute_type_value(&bstr) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(v2) => v == v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infoblock_roundtrips(v: InfoBlock) -> bool {
|
||||||
|
match encode_info_block(ASN1Class::Universal, &v) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(bstr) =>
|
||||||
|
match decode_info_block(&bstr) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(v2) => v == v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/x509/error.rs
Normal file
53
src/x509/error.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
use dsa::rfc6979::DSADecodeError;
|
||||||
|
use ecdsa::ECDSADecodeErr;
|
||||||
|
use rsa::RSAError;
|
||||||
|
use simple_asn1::{ASN1DecodeErr,ASN1EncodeErr};
|
||||||
|
|
||||||
|
/// The error type for parsing and validating an X.509 certificate.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum X509ParseError {
|
||||||
|
ASN1DecodeError(ASN1DecodeErr), ASN1EncodeError(ASN1EncodeErr),
|
||||||
|
RSAError(RSAError), DSADecodeError(DSADecodeError), ECDSADecodeError(ECDSADecodeErr),
|
||||||
|
RSASignatureWrong, DSASignatureWrong,
|
||||||
|
NotEnoughData,
|
||||||
|
IllFormedName, IllFormedAttrTypeValue, IllFormedInfoBlock,
|
||||||
|
IllFormedValidity, IllFormedCertificateInfo, IllFormedSerialNumber,
|
||||||
|
IllFormedAlgoInfo, IllFormedKey, IllFormedEverything,
|
||||||
|
IllegalStringValue, NoSerialNumber, InvalidDSAInfo, ItemNotFound,
|
||||||
|
UnknownAlgorithm, InvalidRSAKey, InvalidDSAKey, InvalidSignatureData,
|
||||||
|
InvalidSignatureHash, InvalidECDSAKey, InvalidPointForm,
|
||||||
|
UnknownEllipticCurve,
|
||||||
|
CompressedPointUnsupported,
|
||||||
|
KeyNotFound,
|
||||||
|
SignatureNotFound, SignatureVerificationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1DecodeErr> for X509ParseError {
|
||||||
|
fn from(e: ASN1DecodeErr) -> X509ParseError {
|
||||||
|
X509ParseError::ASN1DecodeError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1EncodeErr> for X509ParseError {
|
||||||
|
fn from(e: ASN1EncodeErr) -> X509ParseError {
|
||||||
|
X509ParseError::ASN1EncodeError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RSAError> for X509ParseError {
|
||||||
|
fn from(e: RSAError) -> X509ParseError {
|
||||||
|
X509ParseError::RSAError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ECDSADecodeErr> for X509ParseError {
|
||||||
|
fn from(e: ECDSADecodeErr) -> X509ParseError {
|
||||||
|
X509ParseError::ECDSADecodeError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DSADecodeError> for X509ParseError {
|
||||||
|
fn from(e: DSADecodeError) -> X509ParseError {
|
||||||
|
X509ParseError::DSADecodeError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
195
src/x509/misc.rs
Normal file
195
src/x509/misc.rs
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
use num::{BigInt,BigUint,One,ToPrimitive,Zero};
|
||||||
|
use num::bigint::ToBigInt;
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
|
pub enum X509Version { V1, V2, V3 }
|
||||||
|
|
||||||
|
fn decode_version(bs: &[ASN1Block])
|
||||||
|
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match bs.split_first() {
|
||||||
|
Some((&ASN1Block::Integer(_, _, ref v), rest)) => {
|
||||||
|
match v.to_u8() {
|
||||||
|
Some(0) => Ok((X509Version::V1, rest)),
|
||||||
|
Some(1) => Ok((X509Version::V2, rest)),
|
||||||
|
Some(2) => Ok((X509Version::V3, rest)),
|
||||||
|
_ => Ok((X509Version::V1, &bs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::NotEnoughData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for X509Version {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
decode_version(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_version(c: ASN1Class, v: X509Version) -> Vec<ASN1Block> {
|
||||||
|
match v {
|
||||||
|
X509Version::V1 => {
|
||||||
|
let zero: BigInt = Zero::zero();
|
||||||
|
let block = ASN1Block::Integer(c, 0, zero);
|
||||||
|
vec![block]
|
||||||
|
}
|
||||||
|
X509Version::V2 => {
|
||||||
|
let one: BigInt = One::one();
|
||||||
|
let block = ASN1Block::Integer(c, 0, one);
|
||||||
|
vec![block]
|
||||||
|
}
|
||||||
|
X509Version::V3 => {
|
||||||
|
let two: BigInt = BigInt::from(2 as u64);
|
||||||
|
let block = ASN1Block::Integer(c, 0, two);
|
||||||
|
vec![block]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for X509Version {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
Ok(encode_version(c, *self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct X509Serial {
|
||||||
|
num: BigUint
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_serial(x: &ASN1Block)
|
||||||
|
-> Result<X509Serial,X509ParseError>
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
&ASN1Block::Integer(_, _, ref v) => {
|
||||||
|
match v.to_biguint() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::IllFormedSerialNumber),
|
||||||
|
Some(n) =>
|
||||||
|
Ok(X509Serial{ num: n })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::NoSerialNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for X509Serial {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(X509Serial,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match v.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NoSerialNumber),
|
||||||
|
Some((x, rest)) => {
|
||||||
|
let v = decode_serial(x)?;
|
||||||
|
Ok((v, rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SerialEncodeErr { ASN1Error(ASN1EncodeErr), InvalidSerialNumber }
|
||||||
|
|
||||||
|
impl From<ASN1EncodeErr> for SerialEncodeErr {
|
||||||
|
fn from(e: ASN1EncodeErr) -> SerialEncodeErr {
|
||||||
|
SerialEncodeErr::ASN1Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_serial(c: ASN1Class, serial: &X509Serial)
|
||||||
|
-> Result<ASN1Block,SerialEncodeErr>
|
||||||
|
{
|
||||||
|
match serial.num.to_bigint() {
|
||||||
|
None =>
|
||||||
|
Err(SerialEncodeErr::InvalidSerialNumber),
|
||||||
|
Some(n) =>
|
||||||
|
Ok(ASN1Block::Integer(c, 0, n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for X509Serial {
|
||||||
|
type Error = SerialEncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,SerialEncodeErr>
|
||||||
|
{
|
||||||
|
let v = encode_serial(c, self)?;
|
||||||
|
Ok(vec![v])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_signature(x: &ASN1Block)
|
||||||
|
-> Result<Vec<u8>,X509ParseError>
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
&ASN1Block::BitString(_, _, size, ref sig) if size % 8 == 0 => {
|
||||||
|
Ok(sig.to_vec())
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::SignatureNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::distributions::Uniform;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn check_version_roundtrip(v: X509Version) {
|
||||||
|
let blocks = encode_version(ASN1Class::Universal, v);
|
||||||
|
match decode_version(&blocks) {
|
||||||
|
Err(_) =>
|
||||||
|
assert!(false),
|
||||||
|
Ok((v2,_)) =>
|
||||||
|
assert_eq!(v, v2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn versions_roundtrip() {
|
||||||
|
check_version_roundtrip(X509Version::V1);
|
||||||
|
check_version_roundtrip(X509Version::V2);
|
||||||
|
check_version_roundtrip(X509Version::V3);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arbitrary for X509Serial {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> X509Serial {
|
||||||
|
let count = g.gen_range(0,16);
|
||||||
|
let dist = Uniform::new_inclusive(0,255);
|
||||||
|
let bits = g.sample_iter(&dist).take(count).collect();
|
||||||
|
let val = BigUint::new(bits);
|
||||||
|
X509Serial{ num: val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn serial_roundtrips(s: X509Serial) -> bool {
|
||||||
|
match encode_serial(ASN1Class::Universal, &s) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(block) =>
|
||||||
|
match decode_serial(&block) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(s2) => s == s2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
301
src/x509/mod.rs
Normal file
301
src/x509/mod.rs
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
mod algident;
|
||||||
|
mod atv;
|
||||||
|
mod error;
|
||||||
|
mod misc;
|
||||||
|
mod name;
|
||||||
|
mod publickey;
|
||||||
|
mod validity;
|
||||||
|
|
||||||
|
use dsa::{DSAPublic,DSAPublicKey};
|
||||||
|
use ecdsa::{ECDSAPublic,ECCPublicKey};
|
||||||
|
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
|
||||||
|
use sha1::Sha1;
|
||||||
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
|
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
||||||
|
use x509::validity::Validity;
|
||||||
|
use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo,
|
||||||
|
decode_algorithm_ident};
|
||||||
|
use x509::atv::InfoBlock;
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
use x509::misc::{X509Serial,X509Version,decode_signature};
|
||||||
|
use x509::publickey::X509PublicKey;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* The actual certificate data type and methods
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/// The type of an X.509 certificate.
|
||||||
|
pub struct GenericCertificate {
|
||||||
|
pub version: X509Version,
|
||||||
|
pub serial: X509Serial,
|
||||||
|
pub signature_alg: AlgorithmIdentifier,
|
||||||
|
pub issuer: InfoBlock,
|
||||||
|
pub subject: InfoBlock,
|
||||||
|
pub validity: Validity,
|
||||||
|
pub subject_key: X509PublicKey,
|
||||||
|
pub extensions: Vec<()>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_certificate(x: &ASN1Block)
|
||||||
|
-> Result<GenericCertificate,X509ParseError>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TBSCertificate ::= SEQUENCE {
|
||||||
|
// version [0] Version DEFAULT v1,
|
||||||
|
// serialNumber CertificateSerialNumber,
|
||||||
|
// signature AlgorithmIdentifier,
|
||||||
|
// issuer Name,
|
||||||
|
// validity Validity,
|
||||||
|
// subject Name,
|
||||||
|
// subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||||
|
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||||
|
// -- If present, version MUST be v2 or v3
|
||||||
|
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||||
|
// -- If present, version MUST be v2 or v3
|
||||||
|
// extensions [3] Extensions OPTIONAL
|
||||||
|
// -- If present, version MUST be v3 -- }
|
||||||
|
//
|
||||||
|
match x {
|
||||||
|
&ASN1Block::Sequence(_, _, ref b0) => {
|
||||||
|
println!("STEP1");
|
||||||
|
let (version, b1) = X509Version::from_asn1(b0)?;
|
||||||
|
println!("STEP2");
|
||||||
|
let (serial, b2) = X509Serial::from_asn1(b1)?;
|
||||||
|
println!("STEP3");
|
||||||
|
let (ident, b3) = AlgorithmIdentifier::from_asn1(b2)?;
|
||||||
|
println!("STEP4");
|
||||||
|
let (issuer, b4) = InfoBlock::from_asn1(b3)?;
|
||||||
|
println!("STEP5");
|
||||||
|
let (validity, b5) = Validity::from_asn1(b4)?;
|
||||||
|
println!("STEP6");
|
||||||
|
let (subject, b6) = InfoBlock::from_asn1(b5)?;
|
||||||
|
println!("STEP7");
|
||||||
|
let (subkey, _ ) = X509PublicKey::from_asn1(b6)?;
|
||||||
|
println!("STEP8");
|
||||||
|
Ok(GenericCertificate {
|
||||||
|
version: version,
|
||||||
|
serial: serial,
|
||||||
|
signature_alg: ident,
|
||||||
|
issuer: issuer,
|
||||||
|
subject: subject,
|
||||||
|
validity: validity,
|
||||||
|
subject_key: subkey,
|
||||||
|
extensions: vec![]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedCertificateInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* X.509 parsing routines
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
pub fn parse_x509(buffer: &[u8]) -> Result<GenericCertificate,X509ParseError> {
|
||||||
|
let blocks = from_der(&buffer[..])?;
|
||||||
|
match blocks.first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NotEnoughData),
|
||||||
|
Some(&ASN1Block::Sequence(_, _, ref x)) => {
|
||||||
|
let cert = decode_certificate(&x[0])?;
|
||||||
|
let cert_block_start = x[0].offset();
|
||||||
|
let cert_block_end = x[1].offset();
|
||||||
|
let cert_block = &buffer[cert_block_start..cert_block_end];
|
||||||
|
let alginfo = decode_algorithm_ident(&x[1])?;
|
||||||
|
let sig = decode_signature(&x[2])?;
|
||||||
|
check_signature(&alginfo, &cert.subject_key, cert_block, sig)?;
|
||||||
|
Ok(cert)
|
||||||
|
}
|
||||||
|
Some(_) =>
|
||||||
|
Err(X509ParseError::IllFormedEverything)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_signature(alg: &AlgorithmIdentifier,
|
||||||
|
key: &X509PublicKey,
|
||||||
|
block: &[u8],
|
||||||
|
sig: Vec<u8>)
|
||||||
|
-> Result<(),X509ParseError>
|
||||||
|
{
|
||||||
|
match (alg.algo, key) {
|
||||||
|
(PublicKeyInfo::RSA, &X509PublicKey::RSA(ref key)) => {
|
||||||
|
let sighash = match alg.hash {
|
||||||
|
HashAlgorithm::SHA1 => &SIGNING_HASH_SHA1,
|
||||||
|
HashAlgorithm::SHA224 => &SIGNING_HASH_SHA224,
|
||||||
|
HashAlgorithm::SHA256 => &SIGNING_HASH_SHA256,
|
||||||
|
HashAlgorithm::SHA384 => &SIGNING_HASH_SHA384,
|
||||||
|
HashAlgorithm::SHA512 => &SIGNING_HASH_SHA512,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !key.verify(sighash, block, &sig) {
|
||||||
|
return Err(X509ParseError::RSASignatureWrong);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL1024N160(ref key))) => {
|
||||||
|
let dsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1
|
||||||
|
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224
|
||||||
|
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N224(ref key))) => {
|
||||||
|
let dsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1
|
||||||
|
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224
|
||||||
|
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N256(ref key))) => {
|
||||||
|
let dsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1
|
||||||
|
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224
|
||||||
|
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL3072N256(ref key))) => {
|
||||||
|
let dsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1
|
||||||
|
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224
|
||||||
|
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP192(ref key))) => {
|
||||||
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP224(ref key))) => {
|
||||||
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP256(ref key))) => {
|
||||||
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP384(ref key))) => {
|
||||||
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP521(ref key))) => {
|
||||||
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* Testing is for winners!
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn can_parse(f: &str) -> Result<GenericCertificate,X509ParseError> {
|
||||||
|
let mut fd = File::open(f).unwrap();
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let _amt = fd.read_to_end(&mut buffer);
|
||||||
|
parse_x509(&buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsa_tests() {
|
||||||
|
assert!(can_parse("testdata/x509/rsa2048-1.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/rsa2048-2.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/rsa4096-1.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/rsa4096-2.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/rsa4096-3.der").is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dsa_tests() {
|
||||||
|
assert!(can_parse("testdata/x509/dsa2048-1.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/dsa2048-2.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/dsa3072-1.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/dsa3072-2.der").is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ecc_tests() {
|
||||||
|
assert!(can_parse("testdata/x509/ec384-1.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/ec384-2.der").is_ok());
|
||||||
|
assert!(can_parse("testdata/x509/ec384-3.der").is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
136
src/x509/name.rs
Normal file
136
src/x509/name.rs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
use num::BigUint;
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
#[derive(Copy,Clone,Debug,Eq,Hash,PartialEq)]
|
||||||
|
pub enum X520Name {
|
||||||
|
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
|
||||||
|
LocalityName, StateOrProvinceName, OrganizationName, OrganizationalUnit,
|
||||||
|
Title, DNQualifier, CountryName, SerialNumber, Pseudonym, DomainComponent,
|
||||||
|
EmailAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for X520Name {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(X520Name,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match v.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NotEnoughData),
|
||||||
|
Some((x,rest)) => {
|
||||||
|
let name = decode_name(&x)?;
|
||||||
|
Ok((name,rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_name(val: &ASN1Block)
|
||||||
|
-> Result<X520Name,X509ParseError>
|
||||||
|
{
|
||||||
|
match val {
|
||||||
|
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
|
||||||
|
if oid == oid!(2,5,4,41) {return Ok(X520Name::Name) }
|
||||||
|
if oid == oid!(2,5,4,4) {return Ok(X520Name::Surname) }
|
||||||
|
if oid == oid!(2,5,4,42) {return Ok(X520Name::GivenName) }
|
||||||
|
if oid == oid!(2,5,4,43) {return Ok(X520Name::Initials) }
|
||||||
|
if oid == oid!(2,5,4,44) {return Ok(X520Name::GenerationQualifier)}
|
||||||
|
if oid == oid!(2,5,4,3) {return Ok(X520Name::CommonName) }
|
||||||
|
if oid == oid!(2,5,4,7) {return Ok(X520Name::LocalityName) }
|
||||||
|
if oid == oid!(2,5,4,8) {return Ok(X520Name::StateOrProvinceName)}
|
||||||
|
if oid == oid!(2,5,4,10) {return Ok(X520Name::OrganizationName) }
|
||||||
|
if oid == oid!(2,5,4,11) {return Ok(X520Name::OrganizationalUnit) }
|
||||||
|
if oid == oid!(2,5,4,12) {return Ok(X520Name::Title) }
|
||||||
|
if oid == oid!(2,5,4,46) {return Ok(X520Name::DNQualifier) }
|
||||||
|
if oid == oid!(2,5,4,6) {return Ok(X520Name::CountryName) }
|
||||||
|
if oid == oid!(2,5,4,5) {return Ok(X520Name::SerialNumber) }
|
||||||
|
if oid == oid!(2,5,4,65) {return Ok(X520Name::Pseudonym) }
|
||||||
|
if oid == oid!(0,9,2342,19200300,100,1,25) {
|
||||||
|
return Ok(X520Name::DomainComponent);
|
||||||
|
}
|
||||||
|
if oid == oid!(1,2,840,113549,1,9,1) {
|
||||||
|
return Ok(X520Name::EmailAddress);
|
||||||
|
}
|
||||||
|
Err(X509ParseError::IllFormedName)
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for X520Name {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let block = encode_name(c, *self);
|
||||||
|
Ok(vec![block])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_name(class: ASN1Class, name: X520Name)
|
||||||
|
-> ASN1Block
|
||||||
|
{
|
||||||
|
let oid = match name {
|
||||||
|
X520Name::Name => oid!(2,5,4,41),
|
||||||
|
X520Name::Surname => oid!(2,5,4,4),
|
||||||
|
X520Name::GivenName => oid!(2,5,4,42),
|
||||||
|
X520Name::Initials => oid!(2,5,4,43),
|
||||||
|
X520Name::GenerationQualifier => oid!(2,5,4,44),
|
||||||
|
X520Name::CommonName => oid!(2,5,4,3),
|
||||||
|
X520Name::LocalityName => oid!(2,5,4,7),
|
||||||
|
X520Name::StateOrProvinceName => oid!(2,5,4,8),
|
||||||
|
X520Name::OrganizationName => oid!(2,5,4,10),
|
||||||
|
X520Name::OrganizationalUnit => oid!(2,5,4,11),
|
||||||
|
X520Name::Title => oid!(2,5,4,12),
|
||||||
|
X520Name::DNQualifier => oid!(2,5,4,46),
|
||||||
|
X520Name::CountryName => oid!(2,5,4,6),
|
||||||
|
X520Name::SerialNumber => oid!(2,5,4,5),
|
||||||
|
X520Name::Pseudonym => oid!(2,5,4,65),
|
||||||
|
X520Name::DomainComponent => oid!(0,9,2342,19200300,100,1,25),
|
||||||
|
X520Name::EmailAddress => oid!(1,2,840,113549,1,9,1)
|
||||||
|
};
|
||||||
|
|
||||||
|
ASN1Block::ObjectIdentifier(class, 0, oid)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn encdec_test(n: X520Name) {
|
||||||
|
let block = encode_name(ASN1Class::Universal, n);
|
||||||
|
let vec = vec![block];
|
||||||
|
match X520Name::from_asn1(&vec) {
|
||||||
|
Err(_) =>
|
||||||
|
assert!(false),
|
||||||
|
Ok((m, _)) =>
|
||||||
|
assert_eq!(n,m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn name_encoding_roundtrips() {
|
||||||
|
encdec_test(X520Name::Name);
|
||||||
|
encdec_test(X520Name::Surname);
|
||||||
|
encdec_test(X520Name::GivenName);
|
||||||
|
encdec_test(X520Name::Initials);
|
||||||
|
encdec_test(X520Name::GenerationQualifier);
|
||||||
|
encdec_test(X520Name::CommonName);
|
||||||
|
encdec_test(X520Name::LocalityName);
|
||||||
|
encdec_test(X520Name::StateOrProvinceName);
|
||||||
|
encdec_test(X520Name::OrganizationName);
|
||||||
|
encdec_test(X520Name::OrganizationalUnit);
|
||||||
|
encdec_test(X520Name::Title);
|
||||||
|
encdec_test(X520Name::DNQualifier);
|
||||||
|
encdec_test(X520Name::CountryName);
|
||||||
|
encdec_test(X520Name::SerialNumber);
|
||||||
|
encdec_test(X520Name::Pseudonym);
|
||||||
|
encdec_test(X520Name::DomainComponent);
|
||||||
|
encdec_test(X520Name::EmailAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
328
src/x509/publickey.rs
Normal file
328
src/x509/publickey.rs
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
|
||||||
|
use dsa::{DSAPublic,DSAPublicKey,DSAPubKey,DSAParameters};
|
||||||
|
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
|
||||||
|
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey};
|
||||||
|
use ecdsa::curve::{P192,P224,P256,P384,P521};
|
||||||
|
use num::BigUint;
|
||||||
|
use rsa::RSAPublic;
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
|
||||||
|
der_decode,der_encode,from_der};
|
||||||
|
use utils::TranslateNums;
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
pub enum X509PublicKey {
|
||||||
|
DSA(DSAPublic),
|
||||||
|
RSA(RSAPublic),
|
||||||
|
ECDSA(ECDSAPublic)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<X509PublicKey> for Option<DSAPublic> {
|
||||||
|
fn from(x: X509PublicKey) -> Option<DSAPublic> {
|
||||||
|
match x {
|
||||||
|
X509PublicKey::DSA(x) => Some(x),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<X509PublicKey> for Option<RSAPublic> {
|
||||||
|
fn from(x: X509PublicKey) -> Option<RSAPublic> {
|
||||||
|
match x {
|
||||||
|
X509PublicKey::RSA(x) => Some(x),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<X509PublicKey> for Option<ECDSAPublic> {
|
||||||
|
fn from(x: X509PublicKey) -> Option<ECDSAPublic> {
|
||||||
|
match x {
|
||||||
|
X509PublicKey::ECDSA(x) => Some(x),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum X509EncodeErr {
|
||||||
|
ASN1EncodeErr(ASN1EncodeErr),
|
||||||
|
ECDSAEncodeErr(ECDSAEncodeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1EncodeErr> for X509EncodeErr {
|
||||||
|
fn from(x: ASN1EncodeErr) -> X509EncodeErr {
|
||||||
|
X509EncodeErr::ASN1EncodeErr(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ECDSAEncodeErr> for X509EncodeErr {
|
||||||
|
fn from(x: ECDSAEncodeErr) -> X509EncodeErr {
|
||||||
|
X509EncodeErr::ECDSAEncodeErr(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for X509PublicKey {
|
||||||
|
type Error = X509EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,X509EncodeErr> {
|
||||||
|
let block = match self {
|
||||||
|
X509PublicKey::RSA(x) => encode_rsa_key(c, x)?,
|
||||||
|
X509PublicKey::DSA(x) => encode_dsa_key(c, x)?,
|
||||||
|
X509PublicKey::ECDSA(x) => encode_ecdsa_key(c, x)?,
|
||||||
|
};
|
||||||
|
Ok(vec![block])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for X509PublicKey {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block]) -> Result<(X509PublicKey, &[ASN1Block]), Self::Error>
|
||||||
|
{
|
||||||
|
let (block, rest) = v.split_first().ok_or(X509ParseError::NotEnoughData)?;
|
||||||
|
|
||||||
|
// SubjectPublicKeyInfo ::= SEQUENCE {
|
||||||
|
// algorithm AlgorithmIdentifier,
|
||||||
|
// subjectPublicKey BIT STRING }
|
||||||
|
if let &ASN1Block::Sequence(_, _, ref info) = block {
|
||||||
|
let (id, malginfo) = strip_algident(&info[0])?;
|
||||||
|
|
||||||
|
if id == oid!(1,2,840,113549,1,1,1) {
|
||||||
|
let key = decode_rsa_key(&info[1])?;
|
||||||
|
return Ok((X509PublicKey::RSA(key), rest));
|
||||||
|
}
|
||||||
|
|
||||||
|
if id == oid!(1,2,840,10040,4,1) {
|
||||||
|
if let Some(alginfo) = malginfo {
|
||||||
|
let key = decode_dsa_key(alginfo, &info[1])?;
|
||||||
|
return Ok((X509PublicKey::DSA(key), rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if id == oid!(1,2,840,10045,2,1) {
|
||||||
|
if let Some(alginfo) = malginfo {
|
||||||
|
let key = decode_ecdsa_key(alginfo, &info[1..])?;
|
||||||
|
return Ok((X509PublicKey::ECDSA(key), rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(X509ParseError::IllFormedKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// RSA Public Key encoding / decoding
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fn encode_rsa_key(c: ASN1Class, x: &RSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,113549,1,1,1));
|
||||||
|
let bstr = der_encode(x)?;
|
||||||
|
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![objoid, objkey]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_rsa_key(x: &ASN1Block) -> Result<RSAPublic,X509ParseError>
|
||||||
|
{
|
||||||
|
if let &ASN1Block::BitString(_, _, _, ref bstr) = x {
|
||||||
|
der_decode(bstr).map_err(|x| X509ParseError::RSAError(x))
|
||||||
|
} else {
|
||||||
|
Err(X509ParseError::NotEnoughData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// DSA Public Key encoding / decoding
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fn encode_dsa_key(c: ASN1Class, x: &DSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10040,4,1));
|
||||||
|
let (mut objparams, bstr) = match x {
|
||||||
|
DSAPublic::DSAPublicL1024N160(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
|
||||||
|
DSAPublic::DSAPublicL2048N224(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
|
||||||
|
DSAPublic::DSAPublicL2048N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
|
||||||
|
DSAPublic::DSAPublicL3072N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?)
|
||||||
|
};
|
||||||
|
objparams.insert(0, objoid);
|
||||||
|
let headinfo = ASN1Block::Sequence(c, 0, objparams);
|
||||||
|
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, vec![headinfo, objkey]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509ParseError>
|
||||||
|
{
|
||||||
|
if let ASN1Block::Sequence(_, _, pqg) = info {
|
||||||
|
if pqg.len() != 3 { return Err(X509ParseError::InvalidDSAInfo); }
|
||||||
|
|
||||||
|
let puint = decode_biguint(&pqg[0])?;
|
||||||
|
let guint = decode_biguint(&pqg[1])?;
|
||||||
|
let quint = decode_biguint(&pqg[2])?;
|
||||||
|
|
||||||
|
if puint.bits() > 2048 {
|
||||||
|
let p = U3072::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let q = U3072::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let params = L3072N256::new(p, q, g);
|
||||||
|
|
||||||
|
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||||
|
let blocks = from_der(ybstr)?;
|
||||||
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
|
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
let key = DSAPubKey::<L3072N256,U3072>::new(params, y);
|
||||||
|
let reskey = DSAPublic::DSAPublicL3072N256(key);
|
||||||
|
return Ok(reskey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(X509ParseError::InvalidDSAKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if puint.bits() > 1024 {
|
||||||
|
if guint.bits() > 224 {
|
||||||
|
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let params = L2048N256::new(p, q, g);
|
||||||
|
|
||||||
|
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||||
|
let blocks = from_der(ybstr)?;
|
||||||
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
|
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
let key = DSAPubKey::<L2048N256,U2048>::new(params, y);
|
||||||
|
let reskey = DSAPublic::DSAPublicL2048N256(key);
|
||||||
|
return Ok(reskey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(X509ParseError::InvalidDSAKey)
|
||||||
|
} else {
|
||||||
|
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let params = L2048N224::new(p, q, g);
|
||||||
|
|
||||||
|
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||||
|
let blocks = from_der(ybstr)?;
|
||||||
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
|
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
let key = DSAPubKey::<L2048N224,U2048>::new(params, y);
|
||||||
|
let reskey = DSAPublic::DSAPublicL2048N224(key);
|
||||||
|
return Ok(reskey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(X509ParseError::InvalidDSAKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = U1024::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let q = U1024::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let g = U192::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||||
|
let params = L1024N160::new(p, q, g);
|
||||||
|
|
||||||
|
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||||
|
let blocks = from_der(ybstr)?;
|
||||||
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
|
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
|
let key = DSAPubKey::<L1024N160,U1024>::new(params, y);
|
||||||
|
let reskey = DSAPublic::DSAPublicL1024N160(key);
|
||||||
|
return Ok(reskey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(X509ParseError::InvalidDSAKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(X509ParseError::InvalidDSAInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// ECDSA Public Key encoding
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fn encode_ecdsa_key(c: ASN1Class, x: &ECDSAPublic) -> Result<ASN1Block,ECDSAEncodeErr>
|
||||||
|
{
|
||||||
|
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
|
||||||
|
let (base_curve_oid, mut keyvec) = match x {
|
||||||
|
ECDSAPublic::ECCPublicP192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
|
||||||
|
ECDSAPublic::ECCPublicP224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
|
||||||
|
ECDSAPublic::ECCPublicP256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
|
||||||
|
ECDSAPublic::ECCPublicP384(k) => (oid!(1,3,132,0,34), k.to_asn1_class(c)?),
|
||||||
|
ECDSAPublic::ECCPublicP521(k) => (oid!(1,3,132,0,35), k.to_asn1_class(c)?),
|
||||||
|
};
|
||||||
|
let curve_oid = ASN1Block::ObjectIdentifier(c, 0, base_curve_oid);
|
||||||
|
let header = ASN1Block::Sequence(c, 0, vec![objoid, curve_oid]);
|
||||||
|
keyvec.insert(0, header);
|
||||||
|
Ok(ASN1Block::Sequence(c, 0, keyvec))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_ecdsa_key(info: ASN1Block, keybls: &[ASN1Block]) -> Result<ECDSAPublic,X509ParseError>
|
||||||
|
{
|
||||||
|
if let ASN1Block::ObjectIdentifier(_, _, oid) = info {
|
||||||
|
if oid == oid!(1,2,840,10045,3,1,1) {
|
||||||
|
let (res, _) = ECCPubKey::<P192>::from_asn1(keybls)?;
|
||||||
|
return Ok(ECDSAPublic::ECCPublicP192(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
if oid == oid!(1,3,132,0,33) {
|
||||||
|
let (res, _) = ECCPubKey::<P224>::from_asn1(keybls)?;
|
||||||
|
return Ok(ECDSAPublic::ECCPublicP224(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
if oid == oid!(1,2,840,10045,3,1,7) {
|
||||||
|
let (res, _) = ECCPubKey::<P256>::from_asn1(keybls)?;
|
||||||
|
return Ok(ECDSAPublic::ECCPublicP256(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
if oid == oid!(1,3,132,0,34) {
|
||||||
|
let (res, _) = ECCPubKey::<P384>::from_asn1(keybls)?;
|
||||||
|
return Ok(ECDSAPublic::ECCPublicP384(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
if oid == oid!(1,3,132,0,35) {
|
||||||
|
let (res, _) = ECCPubKey::<P521>::from_asn1(keybls)?;
|
||||||
|
return Ok(ECDSAPublic::ECCPublicP521(res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(X509ParseError::UnknownEllipticCurve)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strip_algident(block: &ASN1Block)
|
||||||
|
-> Result<(OID, Option<ASN1Block>),X509ParseError>
|
||||||
|
{
|
||||||
|
match block {
|
||||||
|
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
|
||||||
|
Ok((oid.clone(), None))
|
||||||
|
}
|
||||||
|
&ASN1Block::Sequence(_, _, ref items) => {
|
||||||
|
let (oid, _) = strip_algident(&items[0])?;
|
||||||
|
Ok((oid, Some(items[1].clone())))
|
||||||
|
}
|
||||||
|
_ => Err(X509ParseError::IllFormedAlgoInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_biguint(b: &ASN1Block) -> Result<BigUint,X509ParseError> {
|
||||||
|
match b {
|
||||||
|
&ASN1Block::Integer(_, _, ref v) => {
|
||||||
|
match v.to_biguint() {
|
||||||
|
Some(sn) => Ok(sn),
|
||||||
|
_ => Err(X509ParseError::InvalidDSAInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidDSAInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
118
src/x509/validity.rs
Normal file
118
src/x509/validity.rs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
use chrono::{DateTime,Utc};
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct Validity {
|
||||||
|
not_before: DateTime<Utc>,
|
||||||
|
not_after: DateTime<Utc>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_validity_data(bs: &ASN1Block) -> Result<Validity,X509ParseError> {
|
||||||
|
// Validity ::= SEQUENCE {
|
||||||
|
// notBefore Time,
|
||||||
|
// notAfter Time }
|
||||||
|
match bs {
|
||||||
|
&ASN1Block::Sequence(_, _, ref valxs) => {
|
||||||
|
if valxs.len() != 2 {
|
||||||
|
return Err(X509ParseError::IllFormedValidity);
|
||||||
|
}
|
||||||
|
let nb = get_time(&valxs[0])?;
|
||||||
|
let na = get_time(&valxs[1])?;
|
||||||
|
Ok(Validity{ not_before: nb, not_after: na })
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedValidity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for Validity {
|
||||||
|
type Error = X509ParseError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(Validity,&[ASN1Block]),X509ParseError>
|
||||||
|
{
|
||||||
|
match v.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(X509ParseError::NotEnoughData),
|
||||||
|
Some((x, rest)) => {
|
||||||
|
let v = decode_validity_data(&x)?;
|
||||||
|
Ok((v, rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_validity_data(c: ASN1Class, v: &Validity) -> ASN1Block {
|
||||||
|
let mut vs = Vec::with_capacity(2);
|
||||||
|
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_before));
|
||||||
|
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_after));
|
||||||
|
ASN1Block::Sequence(c, 0, vs)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for Validity {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let block = encode_validity_data(c, self);
|
||||||
|
Ok(vec![block])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_time(b: &ASN1Block) -> Result<DateTime<Utc>, X509ParseError> {
|
||||||
|
match b {
|
||||||
|
&ASN1Block::UTCTime(_, _, v) => Ok(v.clone()),
|
||||||
|
&ASN1Block::GeneralizedTime(_, _, v) => Ok(v.clone()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::IllFormedValidity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use chrono::TimeZone;
|
||||||
|
use chrono::offset::LocalResult;
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use rand::Rng;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn arbitrary_date<G: Gen>(g: &mut G) -> DateTime<Utc> {
|
||||||
|
loop {
|
||||||
|
let y = g.gen_range(1900,3000);
|
||||||
|
let mo = g.gen_range(0,12);
|
||||||
|
let d = g.gen_range(0,31);
|
||||||
|
let h = g.gen_range(0,24);
|
||||||
|
let mi = g.gen_range(0,60);
|
||||||
|
let s = g.gen_range(0,60);
|
||||||
|
match Utc.ymd_opt(y,mo,d).and_hms_opt(h,mi,s) {
|
||||||
|
LocalResult::None =>
|
||||||
|
continue,
|
||||||
|
LocalResult::Single(x) =>
|
||||||
|
return x,
|
||||||
|
LocalResult::Ambiguous(x,_) =>
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arbitrary for Validity {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> Validity {
|
||||||
|
Validity {
|
||||||
|
not_before: arbitrary_date(g),
|
||||||
|
not_after: arbitrary_date(g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn validity_roundtrips(v: Validity) -> bool {
|
||||||
|
let bstr = encode_validity_data(ASN1Class::Universal, &v);
|
||||||
|
match decode_validity_data(&bstr) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok(v2) => v == v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
testdata/x509/dsa2048-1.der
vendored
Normal file
BIN
testdata/x509/dsa2048-1.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/dsa2048-2.der
vendored
Normal file
BIN
testdata/x509/dsa2048-2.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/dsa3072-1.der
vendored
Normal file
BIN
testdata/x509/dsa3072-1.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/dsa3072-2.der
vendored
Normal file
BIN
testdata/x509/dsa3072-2.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/ec384-1.der
vendored
Normal file
BIN
testdata/x509/ec384-1.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/ec384-2.der
vendored
Normal file
BIN
testdata/x509/ec384-2.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/ec384-3.der
vendored
Normal file
BIN
testdata/x509/ec384-3.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/rsa2048-1.der
vendored
Normal file
BIN
testdata/x509/rsa2048-1.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/rsa2048-2.der
vendored
Normal file
BIN
testdata/x509/rsa2048-2.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/rsa4096-1.der
vendored
Normal file
BIN
testdata/x509/rsa4096-1.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/rsa4096-2.der
vendored
Normal file
BIN
testdata/x509/rsa4096-2.der
vendored
Normal file
Binary file not shown.
BIN
testdata/x509/rsa4096-3.der
vendored
Normal file
BIN
testdata/x509/rsa4096-3.der
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user