sim: Add test support for x25519 encrypted images

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/sim/Cargo.toml b/sim/Cargo.toml
index 2704de1..b78dd92 100644
--- a/sim/Cargo.toml
+++ b/sim/Cargo.toml
@@ -17,6 +17,7 @@
 enc-rsa = ["mcuboot-sys/enc-rsa"]
 enc-kw = ["mcuboot-sys/enc-kw"]
 enc-ec256 = ["mcuboot-sys/enc-ec256"]
+enc-x25519 = ["mcuboot-sys/enc-x25519"]
 bootstrap = ["mcuboot-sys/bootstrap"]
 multiimage = ["mcuboot-sys/multiimage"]
 large-write = []
diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml
index 9e11191..829d2ec 100644
--- a/sim/mcuboot-sys/Cargo.toml
+++ b/sim/mcuboot-sys/Cargo.toml
@@ -41,6 +41,9 @@
 # Encrypt image in the secondary slot using ECIES-P256
 enc-ec256 = []
 
+# Encrypt image in the secondary slot using ECIES-X25519
+enc-x25519 = []
+
 # Allow bootstrapping an empty/invalid primary slot from a valid secondary slot
 bootstrap = []
 
diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs
index b431cb3..49739f6 100644
--- a/sim/mcuboot-sys/build.rs
+++ b/sim/mcuboot-sys/build.rs
@@ -20,6 +20,7 @@
     let enc_rsa = env::var("CARGO_FEATURE_ENC_RSA").is_ok();
     let enc_kw = env::var("CARGO_FEATURE_ENC_KW").is_ok();
     let enc_ec256 = env::var("CARGO_FEATURE_ENC_EC256").is_ok();
+    let enc_x25519 = env::var("CARGO_FEATURE_ENC_X25519").is_ok();
     let bootstrap = env::var("CARGO_FEATURE_BOOTSTRAP").is_ok();
     let multiimage = env::var("CARGO_FEATURE_MULTIIMAGE").is_ok();
     let downgrade_prevention = env::var("CARGO_FEATURE_DOWNGRADE_PREVENTION").is_ok();
@@ -109,7 +110,7 @@
         conf.file("../../ext/fiat/src/curve25519.c");
         conf.file("../../ext/mbedtls-asn1/src/platform_util.c");
         conf.file("../../ext/mbedtls-asn1/src/asn1parse.c");
-    } else if !enc_ec256 {
+    } else if !enc_ec256 && !enc_x25519 {
         // No signature type, only sha256 validation. The default
         // configuration file bundled with mbedTLS is sufficient.
         // When using ECIES-P256 rely on Tinycrypt.
@@ -214,6 +215,32 @@
         conf.file("../../ext/tinycrypt/lib/source/ecc_dh.c");
     }
 
+    if enc_x25519 {
+        conf.define("MCUBOOT_ENCRYPT_X25519", None);
+        conf.define("MCUBOOT_ENC_IMAGES", None);
+        conf.define("MCUBOOT_USE_TINYCRYPT", None);
+        conf.define("MCUBOOT_SWAP_SAVE_ENCTLV", None);
+
+        conf.file("../../boot/bootutil/src/encrypted.c");
+        conf.file("csupport/keys.c");
+
+        conf.include("../../ext/mbedtls-asn1/include");
+        conf.include("../../ext/tinycrypt/lib/include");
+        conf.include("../../ext/tinycrypt-sha512/lib/include");
+
+        conf.file("../../ext/fiat/src/curve25519.c");
+
+        conf.file("../../ext/tinycrypt/lib/source/utils.c");
+        conf.file("../../ext/tinycrypt/lib/source/sha256.c");
+
+        conf.file("../../ext/mbedtls-asn1/src/platform_util.c");
+        conf.file("../../ext/mbedtls-asn1/src/asn1parse.c");
+
+        conf.file("../../ext/tinycrypt/lib/source/aes_encrypt.c");
+        conf.file("../../ext/tinycrypt/lib/source/aes_decrypt.c");
+        conf.file("../../ext/tinycrypt/lib/source/ctr_mode.c");
+        conf.file("../../ext/tinycrypt/lib/source/hmac.c");
+    }
 
     if sig_rsa && enc_kw {
         conf.define("MBEDTLS_CONFIG_FILE", Some("<config-rsa-kw.h>"));
@@ -221,7 +248,7 @@
         conf.define("MBEDTLS_CONFIG_FILE", Some("<config-rsa.h>"));
     } else if (sig_ecdsa || enc_ec256) && !enc_kw {
         conf.define("MBEDTLS_CONFIG_FILE", Some("<config-asn1.h>"));
-    } else if sig_ed25519 {
+    } else if sig_ed25519 || enc_x25519 {
         conf.define("MBEDTLS_CONFIG_FILE", Some("<config-asn1.h>"));
     } else if enc_kw {
         conf.define("MBEDTLS_CONFIG_FILE", Some("<config-kw.h>"));
diff --git a/sim/src/image.rs b/sim/src/image.rs
index 2c99694..420a14f 100644
--- a/sim/src/image.rs
+++ b/sim/src/image.rs
@@ -1310,6 +1310,12 @@
         } else {
             TlvGen::new_ecies_p256()
         }
+    } else if Caps::EncX25519.present() {
+        if Caps::Ed25519.present() {
+            TlvGen::new_ed25519_ecies_x25519()
+        } else {
+            TlvGen::new_ecies_x25519()
+        }
     } else {
         // The non-encrypted configuration.
         if Caps::RSA2048.present() {
@@ -1331,7 +1337,7 @@
     /// is unencrypted, and slot 1 is encrypted.
     fn find(&self, slot: usize) -> &Vec<u8> {
         let encrypted = Caps::EncRsa.present() || Caps::EncKw.present() ||
-            Caps::EncEc256.present();
+            Caps::EncEc256.present() || Caps::EncX25519.present();
         match (encrypted, slot) {
             (false, _) => &self.plain,
             (true, 0) => &self.plain,
diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs
index c8200e6..23f8bb8 100644
--- a/sim/src/tlv.rs
+++ b/sim/src/tlv.rs
@@ -53,6 +53,7 @@
     ENCRSA2048 = 0x30,
     ENCKW128 = 0x31,
     ENCEC256 = 0x32,
+    ENCX25519 = 0x33,
     DEPENDENCY = 0x40,
 }
 
@@ -222,6 +223,24 @@
             ..Default::default()
         }
     }
+
+    #[allow(dead_code)]
+    pub fn new_ecies_x25519() -> TlvGen {
+        TlvGen {
+            flags: TlvFlags::ENCRYPTED as u32,
+            kinds: vec![TlvKinds::SHA256, TlvKinds::ENCX25519],
+            ..Default::default()
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn new_ed25519_ecies_x25519() -> TlvGen {
+        TlvGen {
+            flags: TlvFlags::ENCRYPTED as u32,
+            kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519, TlvKinds::ENCX25519],
+            ..Default::default()
+        }
+    }
 }
 
 impl ManifestGen for TlvGen {
@@ -480,12 +499,21 @@
             result.extend_from_slice(&encbuf);
         }
 
-        if self.kinds.contains(&TlvKinds::ENCEC256) {
-            let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
+        if self.kinds.contains(&TlvKinds::ENCEC256) || self.kinds.contains(&TlvKinds::ENCX25519) {
+            let key_bytes = if self.kinds.contains(&TlvKinds::ENCEC256) {
+                pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap()
+            } else {
+                pem::parse(include_bytes!("../../enc-x25519-pub.pem").as_ref()).unwrap()
+            };
             assert_eq!(key_bytes.tag, "PUBLIC KEY");
 
             let rng = rand::SystemRandom::new();
-            let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
+            let alg = if self.kinds.contains(&TlvKinds::ENCEC256) {
+                &agreement::ECDH_P256
+            } else {
+                &agreement::X25519
+            };
+            let pk = match agreement::EphemeralPrivateKey::generate(alg, &rng) {
                 Ok(v) => v,
                 Err(_) => panic!("Failed to generate ephemeral keypair"),
             };
@@ -495,7 +523,11 @@
                 Err(_) => panic!("Failed computing ephemeral public key"),
             };
 
-            let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
+            let peer_pubk = if self.kinds.contains(&TlvKinds::ENCEC256) {
+                agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..])
+            } else {
+                agreement::UnparsedPublicKey::new(&agreement::X25519, &key_bytes.contents[12..])
+            };
 
             #[derive(Debug, PartialEq)]
             struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
@@ -539,9 +571,15 @@
             buf.append(&mut tag.as_ref().to_vec());
             buf.append(&mut cipherkey);
 
-            assert!(buf.len() == 113);
-            result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
-            result.write_u16::<LittleEndian>(113).unwrap();
+            if self.kinds.contains(&TlvKinds::ENCEC256) {
+                assert!(buf.len() == 113);
+                result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
+                result.write_u16::<LittleEndian>(113).unwrap();
+            } else {
+                assert!(buf.len() == 80);
+                result.write_u16::<LittleEndian>(TlvKinds::ENCX25519 as u16).unwrap();
+                result.write_u16::<LittleEndian>(80).unwrap();
+            }
             result.extend_from_slice(&buf);
         }