Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support key import #59

Merged
merged 24 commits into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
924c1c0
Test script for key import
zugzwang Apr 12, 2022
8a1e8f8
Add dsm-import command and documentation
zugzwang Apr 12, 2022
6256be9
Unlock, parse TSK, and pass to dsm module
zugzwang Apr 12, 2022
18f4ada
Import RSA primary keys and subkeys, fix RSA CRT coeff
zugzwang Apr 12, 2022
5810d04
Save more data in custom metadata
zugzwang Apr 13, 2022
1869f5e
Don't assume primary key is 'S'
zugzwang Apr 14, 2022
824e017
Use full representation of key flags
zugzwang Apr 14, 2022
aede9bc
Don't assume first subkey is 'Et' or 'Er'
zugzwang Apr 14, 2022
89302fd
Bump version to 0.3.0
zugzwang Apr 14, 2022
8abe4c8
Differentiate between Signer and Certifier
zugzwang Apr 14, 2022
af8a00b
Improve Sobject information (name, description)
zugzwang Apr 14, 2022
b0f4b2e
Support *-25519
zugzwang Apr 14, 2022
094f9fa
Support NistP-*
zugzwang Apr 14, 2022
4ee1637
Several fixes + test script for knownkeys
zugzwang Apr 14, 2022
50cecd2
X25519 private is LITTLE ENDIAN
zugzwang Apr 15, 2022
dc35b70
Use given agreement algorithms for EC
zugzwang Apr 15, 2022
03e6e3c
Refactor duplicate code
zugzwang Apr 15, 2022
2dd6af7
Add more known keys
zugzwang Apr 15, 2022
3b9112a
Replace serde_derive by serde with derive feature
zugzwang May 19, 2022
cc877d6
Update yasna and Makefile
zugzwang May 19, 2022
f150e85
Reuse KeyFlags struct for KeyMetadata
zugzwang May 19, 2022
5162060
Better handle strings in human_readable
zugzwang May 19, 2022
6597df1
Add key generation message
zugzwang May 25, 2022
a28404e
Address review
zugzwang May 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 53 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions openpgp-dsm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "openpgp-dsm"
version = "0.2.1-beta"
version = "0.3.0-beta"
authors = ["zugzwang <[email protected]>"]
edition = "2018"

Expand All @@ -14,6 +14,7 @@ hyper-native-tls = "0.3.0"
ipnetwork = "0.17"
http = "0.2.4"
log = "0.4.14"
num = "0.4.0"
rpassword = "5.0"
spki = "0.4.0"
sequoia-openpgp = { path = "../openpgp", default-features = false }
Expand All @@ -23,7 +24,7 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
uuid = "0.7.4"
yasna = { version = "0.3.2", features = ["num-bigint", "bit-vec"] }
yasna = { version = "0.5.0", features = ["num-bigint", "bit-vec"] }

[features]
default = ["sequoia-openpgp/default"]
Expand Down
124 changes: 106 additions & 18 deletions openpgp-dsm/src/der.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ pub mod parse {
// publicExponent INTEGER -- e
// }
//
yasna::parse_der(&pk.subject_public_key, |reader| {
Ok(reader.read_sequence(|reader| {
yasna::parse_der(pk.subject_public_key, |reader| {
reader.read_sequence(|reader| {
let n = reader.next().read_biguint()?.to_bytes_be();
let e = reader.next().read_u32()?.to_be_bytes().to_vec();
Ok(RsaPub { n, e })
})?)
})
})
.map_err(|e| e.into())
.map_err(|e| anyhow::anyhow!("ASN1 error: {:?}", e))
}

pub fn rsa_private_edpq(buf: &[u8]) -> super::Result<RsaPriv> {
Expand All @@ -65,7 +65,7 @@ pub mod parse {
// coefficient INTEGER -- (inverse of q) mod p
// }
//
Ok(yasna::parse_der(&buf, |reader| {
yasna::parse_der(buf, |reader| {
reader.read_sequence(|reader| {
let _version = reader.next().read_u32()?;
let _n = reader.next().read_biguint()?;
Expand All @@ -79,7 +79,7 @@ pub mod parse {

Ok(RsaPriv { e, d, p, q })
})
})?)
}).map_err(|e| anyhow::anyhow!("ASN1 error: {:?}", e))
}

pub fn ec_point_x_y(buf: &[u8]) -> super::Result<(Vec<u8>, Vec<u8>)> {
Expand Down Expand Up @@ -116,25 +116,25 @@ pub mod parse {
}

pub fn ecdsa_r_s(buf: &[u8]) -> super::Result<(Vec<u8>, Vec<u8>)> {
Ok(yasna::parse_der(&buf, |reader| {
yasna::parse_der(buf, |reader| {
reader.read_sequence(|reader| {
let r = reader.next().read_biguint()?.to_bytes_be();
let s = reader.next().read_biguint()?.to_bytes_be();
Ok((r, s))
})
})?)
}).map_err(|e| anyhow::anyhow!("ASN1 error: {:?}", e))
}

pub fn ec_priv_scalar(buf: &[u8]) -> super::Result<Vec<u8>> {
Ok(yasna::parse_der(&buf, |reader| {
Ok(reader.read_sequence(|reader| {
yasna::parse_der(buf, |reader| {
reader.read_sequence(|reader| {
let _version = reader.next().read_u32()?;
let priv_key = reader.next().read_bytes()?;
let _oid = reader.next().read_tagged_der()?;
let _pk = reader.next().read_tagged_der()?;
Ok(priv_key)
})?)
})?)
})
}).map_err(|e| anyhow::anyhow!("ASN1 error: {:?}", e))
}
}

Expand All @@ -145,14 +145,101 @@ pub mod serialize {
use yasna::models::ObjectIdentifier as Oid;

use sequoia_openpgp::crypto::mpi;
use num::bigint::BigUint;

pub fn rsa_private(
n: &mpi::MPI,
e: &mpi::MPI,
d: &mpi::ProtectedMPI,
p: &mpi::ProtectedMPI,
q: &mpi::ProtectedMPI,
u: &mpi::ProtectedMPI,
) -> Vec<u8> {
let (n, e, d, p, q, u) = (
BigUint::from_bytes_be(n.value()),
BigUint::from_bytes_be(e.value()),
BigUint::from_bytes_be(d.value()),
BigUint::from_bytes_be(p.value()),
BigUint::from_bytes_be(q.value()),
BigUint::from_bytes_be(u.value()),
);

//
// Note that `u` is defined in RFC4880bis 5.6.1 as p⁻¹ (mod q),
// whereas RFC8017 A.1.2 defines the CRT coefficient as q⁻¹ (mod p).
// We can conciliate both views noting that we know `u` such that
//
// up + qk = 1
MihirLuthra marked this conversation as resolved.
Show resolved Hide resolved
// k = - (up - 1)/q (mod p)
// k = p - ((up - 1)/q (mod p))
//
let minus_k = ((u * p.clone() - 1u32) / q.clone()) % p.clone();
let coeff = (p.clone() - minus_k) % p.clone(); // always well-defined
let e1 = d.clone() % (p.clone() - 1u32);
let e2 = d.clone() % (q.clone() - 1u32);
yasna::construct_der(|w| {
w.write_sequence(|w| {
w.next().write_u32(0);
for mpi in [&n, &e, &d, &p, &q, &e1, &e2, &coeff] {
zugzwang marked this conversation as resolved.
Show resolved Hide resolved
w.next().write_biguint(mpi);
}
})
})
}

pub fn ec_private_25519(curve: &Curve, x: Vec<u8>) -> Result<Vec<u8>> {
let opaque_octet_string = yasna::construct_der(|w| {
w.write_bytes(&x);
});

let oid = curve_oid(curve)?;

// RFC8410
Ok(yasna::construct_der(|w|{
w.write_sequence(|w| {
w.next().write_u32(0);
w.next().write_sequence(|w| {
w.next().write_oid(&oid);
});
w.next().write_bytes(&opaque_octet_string);
});
}))
}

pub fn ec_private(
curve: &Curve,
scalar: &mpi::ProtectedMPI,
) -> Result<Vec<u8>> {
let mut d = scalar.value().to_vec();
// For X25519, x is LITTLE ENDIAN!
if curve == &Curve::Cv25519 {
d.reverse();
return ec_private_25519(curve, d);
}
if curve == &Curve::Ed25519 {
return ec_private_25519(curve, d);
}

let oid = curve_oid(curve)?;

// RFC5915
Ok(yasna::construct_der(|w|{
w.write_sequence(|w| {
w.next().write_u32(1);
w.next().write_bytes(&d);
w.next().write_tagged(yasna::Tag::context(0), |w| {
w.write_oid(&oid);
});
// We ignore the public key serialization
});
}))
}

pub fn spki_ecdh(curve: &Curve, e: &mpi::MPI) -> Vec<u8> {
match curve {
Curve::Cv25519 => {
let x = e.value();
if x.len() == 0 {
unreachable!();
}
assert!(!x.is_empty());

let x = x[1..].to_vec();

Expand All @@ -173,7 +260,7 @@ pub mod serialize {
//
let nist_oid = Oid::from_slice(&[1, 2, 840, 10045, 2, 1]);

let named_curve = curve_oid(&curve).expect("bad curve OID");
let named_curve = curve_oid(curve).expect("bad curve OID");

let alg_id = yasna::construct_der(|writer| {
writer.write_sequence(|writer| {
Expand All @@ -182,7 +269,7 @@ pub mod serialize {
});
});

let subj_public_key = BitVec::from_bytes(&e.value());
let subj_public_key = BitVec::from_bytes(e.value());
yasna::construct_der(|writer| {
writer.write_sequence(|writer| {
writer.next().write_der(&alg_id);
Expand All @@ -199,7 +286,8 @@ pub mod serialize {
Curve::NistP384 => Oid::from_slice(&[1, 3, 132, 0, 34]),
Curve::NistP521 => Oid::from_slice(&[1, 3, 132, 0, 35]),
Curve::Cv25519 => Oid::from_slice(&[1, 3, 101, 110]),
curve @ _ => {
Curve::Ed25519 => Oid::from_slice(&[1, 3, 101, 112]),
curve => {
return Err(anyhow::anyhow!("unsupported curve {}", curve));
}
};
Expand Down
Loading