1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
|
extern crate rand;
#[macro_use]
extern crate pretty_assertions;
extern crate serde_json;
#[macro_use]
extern crate serde;
extern crate pgp;
extern crate pretty_env_logger;
#[macro_use]
extern crate log;
use std::fs::File;
use std::io::Read;
use pgp::composed::{Deserializable, Message, SignedPublicKey, SignedSecretKey};
use pgp::types::PublicKeyTrait;
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Testcase {
typ: Option<String>,
decrypt_key: String,
passphrase: String,
verify_key: Option<String>,
filename: Option<String>,
timestamp: Option<u64>,
textcontent: Option<String>,
keyid: Option<String>,
}
fn test_parse_msg(entry: &str, base_path: &str, is_normalized: bool) {
let _ = pretty_env_logger::try_init();
// TODO: verify filename
let n = format!("{base_path}/{entry}");
let mut file = File::open(&n).unwrap_or_else(|_| panic!("no file: {}", &n));
let details: Testcase = serde_json::from_reader(&mut file).unwrap();
info!(
"Testcase: {}",
serde_json::to_string_pretty(&details).unwrap()
);
let mut decrypt_key_file =
File::open(format!("{}/{}", base_path, details.decrypt_key)).unwrap();
let (decrypt_key, _headers) = SignedSecretKey::from_armor_single(&mut decrypt_key_file)
.expect("failed to read decryption key");
decrypt_key.verify().expect("invalid decryption key");
let decrypt_id = hex::encode(decrypt_key.key_id());
info!("decrypt key (ID={})", &decrypt_id);
if let Some(id) = &details.keyid {
assert_eq!(id, &decrypt_id, "invalid keyid");
}
let verify_key = if let Some(verify_key_str) = details.verify_key.clone() {
let mut verify_key_file = File::open(format!("{base_path}/{verify_key_str}")).unwrap();
let (verify_key, _headers) = SignedPublicKey::from_armor_single(&mut verify_key_file)
.expect("failed to read verification key");
verify_key.verify().expect("invalid verification key");
let verify_id = hex::encode(verify_key.key_id());
info!("verify key (ID={})", &verify_id);
Some(verify_key)
} else {
None
};
let file_name = entry.replace(".json", ".asc");
let cipher_file_path = format!("{base_path}/{file_name}");
let mut cipher_file = File::open(&cipher_file_path).unwrap();
let (message, headers) =
Message::from_armor_single(&mut cipher_file).expect("failed to parse message");
info!("message: {:?}", &message);
match &message {
Message::Encrypted { .. } => {
let (decrypted, ids) = message
.decrypt(|| details.passphrase.clone(), &[&decrypt_key])
.expect("failed to init decryption");
assert_eq!(ids.len(), 1);
if let Some(verify_key) = verify_key {
decrypted
.verify(&verify_key.primary_key)
.expect("message verification failed");
}
// serialize and check we get the same thing
let serialized = decrypted.to_armored_bytes(None.into()).unwrap();
// and parse them again
let (decrypted2, _headers) =
Message::from_armor_single(&serialized[..]).expect("failed to parse round2");
assert_eq!(decrypted, decrypted2);
let raw = match decrypted {
Message::Literal(data) => data,
Message::Compressed(data) => {
let m = Message::from_bytes(data.decompress().unwrap()).unwrap();
// serialize and check we get the same thing
let serialized = m.to_armored_bytes(None.into()).unwrap();
// and parse them again
let (m2, _headers) = Message::from_armor_single(&serialized[..])
.expect("failed to parse round3");
assert_eq!(m, m2);
m.get_literal().unwrap().clone()
}
_ => panic!("unexpected message type: {decrypted:?}"),
};
assert_eq!(
::std::str::from_utf8(raw.data()).unwrap(),
details.textcontent.unwrap_or_default()
);
}
Message::Signed { signature, .. } => {
println!("signature: {signature:?}");
}
_ => {
// TODO: some other checks?
panic!("this test should not have anything else?");
}
}
// serialize and check we get the same thing
let serialized = message.to_armored_string(Some(&headers).into()).unwrap();
if is_normalized {
let mut cipher_file = File::open(&cipher_file_path).unwrap();
let mut expected_bytes = String::new();
cipher_file.read_to_string(&mut expected_bytes).unwrap();
// normalize read in line endings to unix
assert_eq!(serialized, expected_bytes.replace("\r\n", "\n"));
}
// and parse them again
let (message2, headers2) =
Message::from_armor_single(serialized.as_bytes()).expect("failed to parse round2");
assert_eq!(headers, headers2);
assert_eq!(message, message2);
}
macro_rules! msg_test {
($name:ident, $pos:expr, $normalized:expr) => {
#[test]
fn $name() {
test_parse_msg(
&format!("{}.json", $pos),
"./tests/openpgp-interop/testcases/messages",
$normalized,
);
}
};
}
// RSA
msg_test!(msg_gnupg_v1_001, "gnupg-v1-001", false);
// Elgamal
// msg_test!(msg_gnupg_v1_002, "gnupg-v1-002", true);
// RSA
msg_test!(msg_gnupg_v1_003, "gnupg-v1-003", false);
msg_test!(msg_gnupg_v1_4_11_001, "gnupg-v1-4-11-001", true);
msg_test!(msg_gnupg_v1_4_11_002, "gnupg-v1-4-11-002", false);
msg_test!(msg_gnupg_v1_4_11_003, "gnupg-v1-4-11-003", true);
msg_test!(msg_gnupg_v1_4_11_004, "gnupg-v1-4-11-004", true);
msg_test!(msg_gnupg_v1_4_11_005, "gnupg-v1-4-11-005", true);
msg_test!(msg_gnupg_v1_4_11_006, "gnupg-v1-4-11-006", false);
msg_test!(msg_gnupg_v2_0_17_001, "gnupg-v2-0-17-001", true);
msg_test!(msg_gnupg_v2_0_17_002, "gnupg-v2-0-17-002", false);
msg_test!(msg_gnupg_v2_0_17_003, "gnupg-v2-0-17-003", true);
msg_test!(msg_gnupg_v2_0_17_004, "gnupg-v2-0-17-004", true);
msg_test!(msg_gnupg_v2_0_17_005, "gnupg-v2-0-17-005", true);
msg_test!(msg_gnupg_v2_0_17_006, "gnupg-v2-0-17-006", true);
// parsing error
// ECDH key - nist p256
// msg_test!(msg_gnupg_v2_1_5_001, "gnupg-v2-1-5-001", true);
// parsing error
// ECDH key - nist p384
// msg_test!(msg_gnupg_v2_1_5_002, "gnupg-v2-1-5-002", true);
// parsing error
// ECDH key - nist p512
// msg_test!(msg_gnupg_v2_1_5_003, "gnupg-v2-1-5-003", true);
msg_test!(msg_gnupg_v2_10_001, "gnupg-v2-10-001", true);
msg_test!(msg_gnupg_v2_10_002, "gnupg-v2-10-002", true);
msg_test!(msg_gnupg_v2_10_003, "gnupg-v2-10-003", true);
msg_test!(msg_gnupg_v2_10_004, "gnupg-v2-10-004", false);
msg_test!(msg_gnupg_v2_10_005, "gnupg-v2-10-005", true);
msg_test!(msg_gnupg_v2_10_006, "gnupg-v2-10-006", true);
msg_test!(msg_gnupg_v2_10_007, "gnupg-v2-10-007", true);
// ECDH
// msg_test!(msg_e2e_001, "e2e-001", true);
// ECDH
// msg_test!(msg_e2e_002, "e2e-001", true);
msg_test!(msg_pgp_10_0_001, "pgp-10-0-001", false);
msg_test!(msg_pgp_10_0_002, "pgp-10-0-002", false);
msg_test!(msg_pgp_10_0_003, "pgp-10-0-003", false);
msg_test!(msg_pgp_10_0_004, "pgp-10-0-004", false);
msg_test!(msg_pgp_10_0_005, "pgp-10-0-005", false);
msg_test!(msg_pgp_10_0_006, "pgp-10-0-006", false);
msg_test!(msg_pgp_10_0_007, "pgp-10-0-007", false);
msg_test!(msg_camellia128_001, "camellia128-001", false);
msg_test!(msg_camellia192_001, "camellia192-001", false);
msg_test!(msg_camellia256_001, "camellia256-001", false);
// ECDH
// msg_test!(msg_openkeychain_001, "openkeychain-001", true);
msg_test!(msg_openpgp_001, "openpgp-001", false);
macro_rules! msg_test_js {
($name:ident, $pos:expr, $normalized:expr) => {
#[test]
fn $name() {
test_parse_msg(&format!("{}.json", $pos), "./tests/openpgpjs", $normalized);
}
};
}
msg_test_js!(msg_openpgpjs_x25519, "x25519", true);
#[test]
fn msg_partial_body_len() {
let mut msg_file = File::open("./tests/partial.asc").unwrap();
Message::from_armor_single(&mut msg_file).expect("failed to parse message");
}
#[test]
fn msg_regression_01() {
let mut msg_file = File::open("./tests/regression-01.asc").unwrap();
Message::from_armor_single(&mut msg_file).expect("failed to parse message");
}
#[test]
fn msg_large_indeterminate_len() {
let _ = pretty_env_logger::try_init();
let mut msg_file = File::open("./tests/indeterminate.asc").unwrap();
let (message, _headers) =
Message::from_armor_single(&mut msg_file).expect("failed to parse message");
let mut key_file = File::open("./tests/openpgpjs/x25519.sec.asc").unwrap();
let (decrypt_key, _headers) =
SignedSecretKey::from_armor_single(&mut key_file).expect("failed to parse key");
let decrypted = message
.decrypt(|| "moon".to_string(), &[&decrypt_key])
.expect("failed to decrypt message")
.0;
let raw = match decrypted {
Message::Literal(data) => data,
Message::Compressed(data) => {
let m = Message::from_bytes(data.decompress().unwrap()).unwrap();
m.get_literal().unwrap().clone()
}
_ => panic!("unexpected message type: {decrypted:?}"),
};
assert_eq!(
::std::str::from_utf8(raw.data()).unwrap(),
"Content-Type: text/plain; charset=us-ascii
Autocrypt-Gossip: addr=deltabot@codespeak.net; keydata=
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
I=
Autocrypt-Gossip: addr=holger@merlinux.eu; keydata=
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
1CvHBWNRmnPMaFMeSpgJ
test1
"
);
}
#[test]
fn msg_literal_signature() {
let (pkey, _) = SignedPublicKey::from_armor_single(
File::open("./tests/autocrypt/alice@autocrypt.example.pub.asc").unwrap(),
)
.unwrap();
let mut msg_file = File::open("./tests/literal-text-signed.asc").unwrap();
let (msg, _) = Message::from_armor_single(&mut msg_file).expect("failed to parse message");
msg.verify(&pkey).unwrap();
}
|