From ab9d51011a8bf31b6ae20a31e00d5ea3c82915d6 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Tue, 18 Feb 2020 14:11:26 -0700 Subject: [PATCH 1/7] Write-up for secure enclaves Signed-off-by: Michael Lodder --- enclave-interface/README.md | 123 ++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 enclave-interface/README.md diff --git a/enclave-interface/README.md b/enclave-interface/README.md new file mode 100644 index 0000000..a656231 --- /dev/null +++ b/enclave-interface/README.md @@ -0,0 +1,123 @@ +# - Feature Name: enclave-interface +- Start Date: 2020-02-11 +- RFC PR: (leave this empty) +- Ursa Issue: (leave this empty) +- Version: 0.1 +- Contributors: Mike Lodder, Jon Geater, Mick Bowman, Carsten Stöcker, Hart Montgomery, Brent Zundel + +# Summary +[summary]: #summary +Hardware security modules(HSM)/Trusted Execution Environments(TEE)/Secure enclaves are becoming more common for specialized cryptography key management. +This RFC describes a common API that can be used for interacting with enclaves in Ursa. This API allows for +HSM/TEE/Enclave providers to be plug and play from a consumer's perspective. This model allows for the programming interface to be +fully harmonised but the implementation can be swapped out at the direction of the application user. + + +# Motivation +[motivation]: #motivation +Using enclaves is difficult. Each provider has unique methods for performing cryptographic operations. +It is the primary aim to abstract away many of the implementation details from developers with the goal of programming an enclave to be easy to +do and misuse resistant. Developers are not usually cryptographic nor key management experts so this API should be +very difficult for people to misuse and create insecure protocols. Ursa will provide a single, central crypto interface +for all to adopt while allowing multiple implementations of that interface that embody different operational or non-functional +characteristics such as instrumentation, tuned performance, or hardware protection. +A good implementation of this pattern should allow different users of the same +compiled code to change the crypto implementation with no ill-effect, and no conditional code in the application itself. + +So why another interface? [PKCS11](http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html) +Microsoft CNG, Java JCA, [Parsec](https://github.com/parallaxsecond/parsec), and others do not handle cross platform, +extensible crypto like Ursa does. For example, HSMs do not currently support BLS signature keys and it is desirable for +applications to take advantage of using hardware-backed or virtual implementations. +Therefore, services that want to use an enclave that have special crypto needs will be able to do so when using Ursa. + + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +The types of hardware-backed or virtual implementations envisaged are: + +1. Simple hardware-accelerations (AES-NI, HW RNGs, FPGAs) +2. Personal HSMs (Yubikey, Ledger, smart card. Typically locally connected, single instance, simple integrated key management, +OS keyrings like Mac OS X Keychain, Gnome-Keyring, KWallet, Windows Credential Manager) +3. Enterprise HSMs (Thales, Iron Core Labs, nCipher, Utimaco, Securosys. May be network connected, multi-user and redundent configurations, complex key management with roles and access policies. Logging and auditing requirements) +4. Cloud key management (Microsoft Azure KeyValut, Amazon AWS KMS, Hashicorp Vault, Box KeySafe) +5. Trusted Execution Environments (Intel SGX, Microsoft CoCo, ARM Trustzone, RISC-V Multivisors, Unbound Key Control) + +Use of each different type of implementation comes with its own unique set of security questions. Superficially a user +may simply want to know **"is my crypto code running in a secure environment or hardware?"**, but for true security +it is necessary to verify many more of the details: + +1. Where did this enclave come from? How was it initialized? +1. What's the administrative status of this service? Who has authority to change the code/firmware/configuration? +1. Can changes to code handling the crypto be detected? +1. How are keys handled? How were they generated? Who has authority to make backups or export or change them? +1. Are whole protocol blocks implemented atomically in the enclave or just individual primitives like encryption? +1. How to prove the enclave is really being used and not bypassed? + +It is very important not to expose the details of the implementation through the API itself: it gets very messy, very quickly +to try to accommodate all the small details of each potential implementation in a generic API. Instead, it is preferable +to protide attestation commands that return provider-specific information which can be verified out-of-band. + +## Why can't we just invisibly use the encalve we find on our system? + +Because, with the possible exception of things like AES-NI or OS TRNG, that's just not possible. +There may be multiple hardwares available, or they may not be discoverable, or they may require out-of-band explicit handling to make them work, or ... (many other reasons). + +## Provider Loading, Program Context, and Session Management + +As soon as a library grows connections or dependencies outside its static code base it becomes necessary to burden it with concepts like context and sessions. +At the very least this is required in order to hold on to things like network connections or other open ports in the case of discrete hardware, but other considerations are: + +1. Login information or live authenticated sessions +1. Use of keys that have extra authorization requirements for use (eg password, MFA) +1. Loadbalancing/failover state + +It should be possible to hide most of this in the provider implementation (putting the burden on the developers and not the user) but inevitably some of this contextual state will need to be carried through the API calls. + +One particular thing to consider is whether we support multiple implementations to be accessed concurrently by the same application. +Consider the case of a Chinese or Russian implementer who needs all the standard core crypto for basic Hyperledger operation but also require GOST or SMx family algorithms for certain purposes. +There are 4 possible naive routes to take here: +1. Do not support sovereign or other 'special' algorithms in Ursa +1. Require all Ursa providers to implement all algorithm families +1. Allow (potentially) multiple providers to be loaded, and have **implicit** selection of which to use depending on the call made +1. Allow (potentially) multiple providers to be loaded, and have **explicit** selection of which to use depending on the knowledge of the developer + +The first three of these are technically feasible but not practically useful. +Ursa will adopt approach #4 and provide an explicit initialization function that specifies which provider is to be used, +and initializes a context object that the application must manage and maintain. +This is, again, in keeping with popular mature crypto architectures such as PKCS11, JCA, and CNG. +The precise manifestation of this will depend on the language bindings for the particular application. + +## Provider requirements and constraints + +Contexts and sessions should **safely** zero out sensitive data when used in memory or disk used to limit side channel attacks like +malicious network and snapshot adversaries or honest but curious system administrators. + +While the main purpose for having a provider architecture is to enable difference between different implementations, it is important to also enforce a significant degree of sameness. +The following constraints are suggested: +1. All providers must provide an implementation of the entire Ursa core interface +1. While a provider may support interactive or 2FA authentication for key use, they must offer a configuration that makes Ursa operation non-interactive +1. All providers must observe data format compatibility in any data element of the published APIs. Assuming the same key is available to both providers, then the output of one provider shall be consumable as input to any other - for example, a signature from provider A shall be verifiable in provider B, and data encrypted in provider B shall be decryptable in provider C. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + + + +# Drawbacks +[drawbacks]: #drawbacks + + +# Rationale and alternatives +[alternatives]: #alternatives + + + +# Prior art +[prior-art]: #prior-art +This provider model is extremely common in the crypto world with implementations like [PKCS11](http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html) +Microsoft CNG, Java JCA, [Parsec](https://github.com/parallaxsecond/parsec), and others. + + +# Unresolved questions +[unresolved]: #unresolved-questions From 00394e21c2293898d308afd801c9f67998989a70 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Tue, 18 Feb 2020 15:35:20 -0700 Subject: [PATCH 2/7] Updates to RFC Signed-off-by: Michael Lodder --- enclave-interface/README.md | 104 +++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/enclave-interface/README.md b/enclave-interface/README.md index a656231..9166797 100644 --- a/enclave-interface/README.md +++ b/enclave-interface/README.md @@ -102,11 +102,111 @@ The following constraints are suggested: # Reference-level explanation [reference-level-explanation]: #reference-level-explanation - +Before any cryptographic operations can occur, programmers must have a connection to the enclave. Enclave connections +come in one of the following forms: + +1. Software Development Kits (SDK) or provider libraries. (SGX, PSP, Trustzone, Mac OS X Keychain) +1. Physical connections (USB) +1. Networked (HTTP, ethernet, bluetooth) + +Therefore initial piece of the interface is the connection. Given each provider has different connection methods, +the connection create process takes a configuration unique to that enclave. + +We show all code samples written as Rust but can be adapted to other languages as desired. + +Most hardware implementations will not allow key material to be passed through the API, even in encrypted form, so a system of external references is required that allows keys to be referenced in a way that supports: +1. **Consistency** - The same ID refers to the same key every time (according to the key management paradigm of the underlying hardware) +1. **Naming schemes** - Organizations often name their keys according to some formal naming scheme - such as **legal.europe.documetencryption.May2019-1**. +1. **Key blocks** - Some HSMs not only allow but actively require keys to be passed as formatted and encrypted keyblocks. In this case we not only need to support the simple data type of a binary key block but also (potentially) identify which KEK it's encrypted under. + +In keeping with the drive for Ursa to be simple and hard to mess up, the proposal is to make KeyIDs in the Ursa interface be simple UTF-8 string names, and leave the underlying provider implementation to deal with the complexities of translation, key rollover, duplication and so on. Keyblocks will not be supported until really demanded. + +The generic trait that all provides the specific APIs is the trait `EnclaveLike`. +```rust +pub trait EnclaveLike { + fn connect(connector: EnclaveConnector) -> Result; + fn close(self); + fn capabilities(&self) -> Result, Error>; + fn create_key(&self, options: EnclaveCreateKeyOptions) -> Result; + fn delete_key(&self, key_id: String) -> Result; + fn execute(&self, message: EnclaveOperation) -> Result; + fn export_wrapped(&self, wrap_key_id: String, key_id: String) -> Result; + fn get_key_info(&self, key_id: String) -> Result; + fn get_public_key(&self, key_id: String) -> Result; + fn get_random(&self, bytes: usize) -> Result; + fn import_wrapped(&self, wrap_key_id: String, wrap_message: EnclaveImportRequest) -> Result; + fn list_keys(&self) -> Result; + fn ping(&self) -> Result; + fn put_key(&self, message: EnclaveMessage) -> Result; + fn reset(&self) -> Result; + fn send_message(&self, message: InputEnclaveMessage) -> Result; +} +``` + +Each connection is provided by the `EnclaveConnector` enumeration. The enumeration defines the connection type. +This list is not exhaustive but is defined enough for the reader to get a general idea of how to add new connection types. +This is where the specifics about the enclave must be known by the developer. +```rust +pub enum EnclaveConnector { + OsKeyRing(OsKeyRingConnector), + YubiHsm(YubiHsmConnector), + SGX(SGXConnector), + Trustzone(TrustzoneConnector), + AwsKms(AwsKmsConnector) +} +``` + +The `OsKeyRingConnector` contains the options for connecting to the OS Keyring which may be backed by a hardware +enclave. Each of these fields may be empty which means the OS will use the default keyring and prompt the consumer +for a username and password. + +```rust +pub struct OsKeyRingConnector { + path: Option, + username: Option, + password: Options +} +``` + +The `YubiHsm` connector contains the options for connecting to a portable Yubikey which may be networked or connected +via USB. Other methods might be provided by the [Yubico SDK](https://developers.yubico.com/YubiHSM2/Releases/) + +```rust +pub struct Credentials { + authentication_key_id: u16, + authentication_key: Key, //derived from PBKDF2 or symmetric key +} + +pub struct UsbConnector { + address: u8, + bus_number: u8, + credentials: Credentials, + context: UsbContext, + product_name: String, + serial_number: u32, + timeout_ms: u64, +} + +pub struct HttpConnector { + address: String, //IP address or DNS name + credentials: Credentials, + port: u16, + timeout_ms: u64 +} + +pub enum YubiHsmConnector { + Usb(UsbConnector), + Http(HttpConnector) +} +``` + +Once a `EnclaveConnector` has been defined, the connection is created. The connection enables the # Drawbacks [drawbacks]: #drawbacks - +For developers intimately familiar with enclave programming, this API may be a more expensive/complicated scheme than +using the methods they are already used to using. Care must be taken so this scheme does not change frequency with each +enclave provider that is to be supported. # Rationale and alternatives [alternatives]: #alternatives From 7511e4c541a6b80f2380aa213fd5f6d3a89ffe9e Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Tue, 18 Feb 2020 15:48:43 -0700 Subject: [PATCH 3/7] Added comments and collapsed some methods Signed-off-by: Michael Lodder --- enclave-interface/README.md | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/enclave-interface/README.md b/enclave-interface/README.md index 9166797..41362a3 100644 --- a/enclave-interface/README.md +++ b/enclave-interface/README.md @@ -124,21 +124,43 @@ In keeping with the drive for Ursa to be simple and hard to mess up, the proposa The generic trait that all provides the specific APIs is the trait `EnclaveLike`. ```rust pub trait EnclaveLike { + /// Create connection to enclave, returns a session/context useful + /// for issuing commands to the enclave fn connect(connector: EnclaveConnector) -> Result; + /// Terminate the current session/context fn close(self); + /// Get a list of capabilities supported by this enclave fn capabilities(&self) -> Result, Error>; + /// Create a new enclave key. Settings and key type and supported operations are + /// defined in the `EnclaveCreateKeyOptions`. fn create_key(&self, options: EnclaveCreateKeyOptions) -> Result; + /// Delete an enclave key. This will error if current session is not allowed fn delete_key(&self, key_id: String) -> Result; + /// Perform a cryptographic operation like encryption, signing, + /// export wrapped, import wrapped, generate attestation, or other crypto algorithms + /// defined in the `EnclaveOperation`. fn execute(&self, message: EnclaveOperation) -> Result; - fn export_wrapped(&self, wrap_key_id: String, key_id: String) -> Result; + /// Get information about the specified "key_id". Such information is + /// key type (Ed25519, RSA, BLS), operations allowed, created date, + /// valid until date, authorized users fn get_key_info(&self, key_id: String) -> Result; + /// Return a public key given a private key with "key_id" fn get_public_key(&self, key_id: String) -> Result; - fn get_random(&self, bytes: usize) -> Result; - fn import_wrapped(&self, wrap_key_id: String, wrap_message: EnclaveImportRequest) -> Result; + /// Return "bytes" random data bytes generated in the enclave + fn get_random(&self, bytes: usize) -> Result, Error>; + /// Return a list of all key_ids the current session is allowed to use fn list_keys(&self) -> Result; + /// Ping the enclave to keep the session/context alive. Returns an error if the session/context is closed + /// or otherwise unavailable fn ping(&self) -> Result; - fn put_key(&self, message: EnclaveMessage) -> Result; + /// Put a raw key into the enclave. Similar to `create_key` except the key was generated outside the enclave. + /// Usually this is used for inserting public or symmetric keys + fn put_key(&self, message: PutKeyOptions) -> Result; + /// Reset the enclave to a factory default state, clearing all stored objects and restoring the default auth key is applicable. + /// WARNING: This wipes all keys and other data (logs, policies) from the enclave. fn reset(&self) -> Result; + /// Useful for non crypto related queries like get audit logs, get storage capacity, or device info as well as + /// creating other credentials, changing permissions and policies. fn send_message(&self, message: InputEnclaveMessage) -> Result; } ``` From 6f93914ec372cf97a5dbb9e54a9e3e5b380999c4 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 19 Feb 2020 13:21:06 -0700 Subject: [PATCH 4/7] More updates Signed-off-by: Michael Lodder --- enclave-interface/README.md | 146 +++++++++++++++++++++++++++++++++--- 1 file changed, 135 insertions(+), 11 deletions(-) diff --git a/enclave-interface/README.md b/enclave-interface/README.md index 41362a3..470633d 100644 --- a/enclave-interface/README.md +++ b/enclave-interface/README.md @@ -39,9 +39,10 @@ The types of hardware-backed or virtual implementations envisaged are: 1. Simple hardware-accelerations (AES-NI, HW RNGs, FPGAs) 2. Personal HSMs (Yubikey, Ledger, smart card. Typically locally connected, single instance, simple integrated key management, OS keyrings like Mac OS X Keychain, Gnome-Keyring, KWallet, Windows Credential Manager) -3. Enterprise HSMs (Thales, Iron Core Labs, nCipher, Utimaco, Securosys. May be network connected, multi-user and redundent configurations, complex key management with roles and access policies. Logging and auditing requirements) -4. Cloud key management (Microsoft Azure KeyValut, Amazon AWS KMS, Hashicorp Vault, Box KeySafe) -5. Trusted Execution Environments (Intel SGX, Microsoft CoCo, ARM Trustzone, RISC-V Multivisors, Unbound Key Control) +3. Enterprise HSMs (Thales, Iron Core Labs, nCipher, Utimaco, Securosys, Jitsuin. + May be network connected, multi-user and redundent configurations, complex key management with roles and access policies. Logging and auditing requirements) +4. Cloud key management (Microsoft Azure KeyVault, Amazon AWS KMS, Hashicorp Vault, Box KeySafe) +5. Trusted Execution Environments (Intel SGX, ARM Trustzone, RISC-V Multivisors, Unbound Key Control) Use of each different type of implementation comes with its own unique set of security questions. Superficially a user may simply want to know **"is my crypto code running in a secure environment or hardware?"**, but for true security @@ -56,7 +57,7 @@ it is necessary to verify many more of the details: It is very important not to expose the details of the implementation through the API itself: it gets very messy, very quickly to try to accommodate all the small details of each potential implementation in a generic API. Instead, it is preferable -to protide attestation commands that return provider-specific information which can be verified out-of-band. +to provide attestation commands that return provider-specific information which can be verified out-of-band. ## Why can't we just invisibly use the encalve we find on our system? @@ -110,13 +111,14 @@ come in one of the following forms: 1. Networked (HTTP, ethernet, bluetooth) Therefore initial piece of the interface is the connection. Given each provider has different connection methods, -the connection create process takes a configuration unique to that enclave. +the connection create process takes a configuration unique to that enclave. The goal of this API design is to minimize +changes to it to maintain compatibility. We show all code samples written as Rust but can be adapted to other languages as desired. Most hardware implementations will not allow key material to be passed through the API, even in encrypted form, so a system of external references is required that allows keys to be referenced in a way that supports: 1. **Consistency** - The same ID refers to the same key every time (according to the key management paradigm of the underlying hardware) -1. **Naming schemes** - Organizations often name their keys according to some formal naming scheme - such as **legal.europe.documetencryption.May2019-1**. +1. **Naming schemes** - Organizations often name their keys according to some formal naming scheme - such as **legal.europe.documentencryption.May2019-1**. 1. **Key blocks** - Some HSMs not only allow but actively require keys to be passed as formatted and encrypted keyblocks. In this case we not only need to support the simple data type of a binary key block but also (potentially) identify which KEK it's encrypted under. In keeping with the drive for Ursa to be simple and hard to mess up, the proposal is to make KeyIDs in the Ursa interface be simple UTF-8 string names, and leave the underlying provider implementation to deal with the complexities of translation, key rollover, duplication and so on. Keyblocks will not be supported until really demanded. @@ -130,7 +132,7 @@ pub trait EnclaveLike { /// Terminate the current session/context fn close(self); /// Get a list of capabilities supported by this enclave - fn capabilities(&self) -> Result, Error>; + fn capabilities(&self) -> Result, Error>; /// Create a new enclave key. Settings and key type and supported operations are /// defined in the `EnclaveCreateKeyOptions`. fn create_key(&self, options: EnclaveCreateKeyOptions) -> Result; @@ -174,7 +176,9 @@ pub enum EnclaveConnector { YubiHsm(YubiHsmConnector), SGX(SGXConnector), Trustzone(TrustzoneConnector), - AwsKms(AwsKmsConnector) + AwsKms(AwsKmsConnector), + AzureKeyVault(AzureKeyVaultConnector), + HashicorpVault(HashicorpConnector) } ``` @@ -222,7 +226,124 @@ pub enum YubiHsmConnector { } ``` -Once a `EnclaveConnector` has been defined, the connection is created. The connection enables the +Once a `EnclaveConnector` has been defined, the connection is created. The connection enables all other operations. +Enclave providers must be queryable for capabilities which can then be used by the caller to determine what its allowed +to use. Common capabilities with existing enclaves are in the following rust code. These are not mutually exclusive +```rust +pub enum EnclaveOperation { + DeriveDiffieHellman(DeriveParams), + GenerateAsymmetricKey(GenerateAsymmetricParams), + GenerateSymmetricKey(GenerateSymmetricParams), + GenerateRandom(RandomParams), + Attestation(AttestationParams), + Sign(SigningParams), + Verify(VerifyParams), + Encrypt(EncryptParams), + Decrypt(DecryptParams), + DeleteKey(DeleteKeyParams), + WrapKey(WrapParams), + UnwrapKey(UnwrapParams), + ExportWrappedKey(ExportWrappedParams), + ImportWrappedKey(ImportWrappedParams), + KeyInfo(KeyInfoParams), + Audit(AuditParams), + Log(LogParams), + DeviceInfo +} + +pub enum DeriveParams { + Pkcs3(Pkcs3Params), + Ecdh(EcdhParams), + Pq(PostQuantumParams) +} + +/// PKCS#3 parameters according to v1.4 +pub struct Pkcs3Params { + /// Prime, must be 2048, 3072, 4096, 6144, or 8192 + p: Pkcs3DhP, + /// Base + g: BigNum, + /// This enclave's key id + id: String, + /// Other's public key + peer: BigNum +} + +/// Pkcs3 diffie hellman prime +pub struct Pkcs3DhP { + value: BigNum +} + +/// Elliptic Curve Diffie Hellman parameters +pub struct EcdhParams { + /// The curve to use + curve: EccCurve, + /// This enclave's key id + id: String, + /// Other's public key as an uncompressed point for curves that support compressed points + /// typically is 57, 65, 97, 129, 133, 193 bytes + peer: EcPoint +} + +/// Valid elliptic curves see https://eprint.iacr.org/2018/193.pdf +/// and https://eprint.iacr.org/2005/133.pdf +/// for information about BN and BLS curves +pub enum EccCurve { + /// Curve25519 + Curve25519, + /// Curve41417 + Curve41417, + /// Curve448 AKA Goldilocks + Curve448, + /// Barreto-Lynn-Scott embedding degree 12 with prime field 381 bits + Bls381, + /// Barreto-Lynn-Scott embedding degree 12 with prime field 461 bits + Bls461, + /// Barreto-Lynn-Scott embedding degree 24 with equivalent security of AES-192 + Bls24, + /// Barreto-Lynn-Scott embedding degree 48 with equivalent security of AES-256 with 581 bit prime + /// see https://tools.ietf.org/id/draft-kato-threat-pairing-01.html#rfc.section.3 + Bls48, + /// Barreto Naehrig with prime field 254 bits. About 100 bits of security + Bn254, + /// Barreto Naehrig with prime field 256 bits. See https://cryptojedi.org/papers/dclxvi-20100714.pdf + /// and https://moderncrypto.org/mail-archive/curves/2016/000740.html for more details + BnP256, + /// Barreto Naehrig with prime field 384 bits. See https://cryptojedi.org/papers/dclxvi-20100714.pdf + BnP384, + /// Barreto Naehrig with prime field 512 bits as specified in ISO15946-5 + BnP512, + /// Barreto Naehrig with prime field 638 bits as specified in + /// https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-ecdaa-algorithm-v2.0-rd-20180702.html#supported-curves-for-ecdaa + BnP638, + /// NIST P-224 (secp224r1) + EcP224, + /// NIST P-256 (secp256r1, prime256v1) + EcP256, + /// NIST P-384 (secp384r1) + EcP384, + /// NIST P-521 (secp521r1) + EcP521, + /// secp256k1 + EcK256, + /// Brainpool 224 + EcBP224, + /// BrainPool 256 + EcBP256, + /// BrainPool 384 + EcBP384, + /// BrainPool 512 + EcBP512, +} +``` + +Some capabilities offer multiple options like `DeriveDiffieHellman` which can be either PKCS#3 DHParameter structure +or Elliptic-Curve based. + +This model allows the flexibility to add new operations and types without changing the APIs. + +Each operation will return an Enclave Message that contains the results or an error upon failure. For example, +Encryption will return the ciphertext and possibly an authentication tag. Signing returns the signature. # Drawbacks [drawbacks]: #drawbacks @@ -230,11 +351,14 @@ For developers intimately familiar with enclave programming, this API may be a m using the methods they are already used to using. Care must be taken so this scheme does not change frequency with each enclave provider that is to be supported. +Another possibility is that this approach is too flexible and requires intimate knowledge about crypto algorithms. +To mitigate this, predefined ciphers can be created for end consumers like RSA-3072-PSS-SHA256 or +AES-256-GCM or AES-128-CBC-HMAC-SHA256 or XCHACHA20-POLY1305. This reduces algorithmic agility that is an inherent problem +with many cryptographic libraries. + # Rationale and alternatives [alternatives]: #alternatives - - # Prior art [prior-art]: #prior-art This provider model is extremely common in the crypto world with implementations like [PKCS11](http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html) From 3a82c68a73671417ddeafdacc6620e648085e569 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Thu, 20 Feb 2020 10:04:03 -0700 Subject: [PATCH 5/7] Changed Derive to Key Agreement Signed-off-by: Michael Lodder --- enclave-interface/README.md | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/enclave-interface/README.md b/enclave-interface/README.md index 470633d..0679126 100644 --- a/enclave-interface/README.md +++ b/enclave-interface/README.md @@ -231,11 +231,11 @@ Enclave providers must be queryable for capabilities which can then be used by t to use. Common capabilities with existing enclaves are in the following rust code. These are not mutually exclusive ```rust pub enum EnclaveOperation { - DeriveDiffieHellman(DeriveParams), + Attestation(AttestationParams), GenerateAsymmetricKey(GenerateAsymmetricParams), GenerateSymmetricKey(GenerateSymmetricParams), GenerateRandom(RandomParams), - Attestation(AttestationParams), + KeyAgreement(AgreementParams), Sign(SigningParams), Verify(VerifyParams), Encrypt(EncryptParams), @@ -251,9 +251,13 @@ pub enum EnclaveOperation { DeviceInfo } -pub enum DeriveParams { +/// Key agreement derivation parameters +pub enum AgreementParams { + /// Key agreement using PKCS3 Pkcs3(Pkcs3Params), + /// Key agreement using ECDH Ecdh(EcdhParams), + /// Key agreement using Post-Quantum algorithms Pq(PostQuantumParams) } @@ -265,8 +269,10 @@ pub struct Pkcs3Params { g: BigNum, /// This enclave's key id id: String, + /// Mask generating function + mgf: Pkcs3Mgf, /// Other's public key - peer: BigNum + peer: BigNum, } /// Pkcs3 diffie hellman prime @@ -274,12 +280,22 @@ pub struct Pkcs3DhP { value: BigNum } +/// Valid mask generating functions for Pkcs3 +pub enum Pkcs3Mgf { + Sha224, + Sha256, + Sha384, + Sha512 +} + /// Elliptic Curve Diffie Hellman parameters pub struct EcdhParams { /// The curve to use curve: EccCurve, /// This enclave's key id id: String, + /// Mask generating function + mgf: EcdhMgf, /// Other's public key as an uncompressed point for curves that support compressed points /// typically is 57, 65, 97, 129, 133, 193 bytes peer: EcPoint @@ -335,6 +351,23 @@ pub enum EccCurve { /// BrainPool 512 EcBP512, } + +/// Valid mask generating functions for Ecdh +pub enum EcdhMgf { + Sha2_224, + Sha2_256, + Sha2_384, + Sha2_512, + Sha3_224, + Sha3_256, + Sha3_384, + Sha3_512, + Blake2_224, + Blake2_256, + Blake2_384, + Blake2_512, + Blake3_256, +} ``` Some capabilities offer multiple options like `DeriveDiffieHellman` which can be either PKCS#3 DHParameter structure @@ -353,7 +386,8 @@ enclave provider that is to be supported. Another possibility is that this approach is too flexible and requires intimate knowledge about crypto algorithms. To mitigate this, predefined ciphers can be created for end consumers like RSA-3072-PSS-SHA256 or -AES-256-GCM or AES-128-CBC-HMAC-SHA256 or XCHACHA20-POLY1305. This reduces algorithmic agility that is an inherent problem +AES-256-GCM, AES-128-CBC-HMAC-SHA256, XCHACHA20-POLY1305, ED25519, ECDSA-SHA256, or ECIES-SHA512-AES-GCM. +This reduces algorithmic agility that is an inherent problem with many cryptographic libraries. # Rationale and alternatives From c262d4a949210ca8adb876ce828a492ef44629ec Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Tue, 16 Jun 2020 06:51:27 -0600 Subject: [PATCH 6/7] Add RFC for zmix layout Signed-off-by: Michael Lodder --- text/0002-zmix-api/README.md | 135 +++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 text/0002-zmix-api/README.md diff --git a/text/0002-zmix-api/README.md b/text/0002-zmix-api/README.md new file mode 100644 index 0000000..142a68e --- /dev/null +++ b/text/0002-zmix-api/README.md @@ -0,0 +1,135 @@ +- Feature Name: Zmix project API and layout +- Start Date: 2020-06-15 +- RFC PR: +- Ursa Issue: +- Version: 1 + +# Summary +[summary]: #summary + +Zmix aims to provide a common API that provide zero-knowledge proofs based on three distinct but not exclusive roles: + +- Issuer: any entity that issues credentials to holders. Issuers control what types of signatures to use, to whom they issue, +criteria for issuance, credential validity periods, and revocation registries if desired. +- Holder/Prover: any entity that manages credentials or secrets to prove to another party in zero-knowledge information about themselves or others +- Verifier: any entity that checks zero-knowledge proofs and is convinced of their truthfulness or not. + +# Motivation +[motivation]: #motivation + +Ursa is beginning to have many primitives that serve to construct a la carte zero-knowledge methods. +Unfortunately, there hasn't been a project plan until now for organizing and layering these primitives together. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Zero-knowledge proofs can be divided into the following categories: + +- Predicates: prove knowledge about statements like inequalities, ranges, andd set memberships +- Knowledge proofs: prove knowledge about statements like signatures and commitments. + +Knowledge proofs tend to center around using credentials like cryptographic signatures and proving knowledge of the signature +instead of revealing it or knowledge of committed values. Signatures may be generated by third-parties (Issuers) or self-attested +by the Provers themselves. Credentials are signatures over 1 or more attributes or claims. Attributes may or may not be disclosed +in a proof but that is the extend of knowledge proofs. + +Predicate proofs tend to center around proving subsets of details about attributes or data in credentials without revealing the entire +value. For example, revocation can be verified without revealing the credential identification number against a specific registry or +the expiration date can be checked if the current date is less than the credentials validity period. + +## Issuers +[issuers]: #issuers +Issuers have the most complicated role due to the necessity of publishing signature verification keys to trusted oracles +either under their control or another trusted party, managing to whom the credentials have been given, to be able to revoke them if incorrect data +is signed or in the case of credential abuse or fraud. This RFC defines all functions needed by Issuers + +- GenerateKeys: Create digital signature keys +- GenerateSign: Create a digital signature +- GenerateBlindSign: Create a blind digital signature +- RevokeSignature: Revoke a digital signature either for incorrect data or behavior +- UpdateKeys: Change digital signature keys to new keys or nullify to revoke +- GenerateRevocationRegistry: Create a revocation registry used for checking if a digital signature is currently vali +- UpdateRevocationRegistry: Add or remove entries in a revocation registry or nullify to invalidate + +## Holders +[holders]: #holders + +Holders are the most involved role in a zero-knowledge proof system. They hold data and prove statements about them to verifiers. +Holders may receive credentials from other Issuers or self-attest data. This RFC defines all functions needed by Holders: + +- PrepareBlindSign: Prepare data to be signed blindly by an Issuer +- UnblindSignature: Unblind a blind signature received from an Issuer +- GenerateSPoK: Create a zero-knowledge proof for a signature +- GeneratePoCV: Create a zero-knowledge proof of committed values +- GeneratePredicate: Create a predicate proof + +## Verifiers +[verifiers]: #verifiers + +Verifiers validate received proofs and signatures. This RFC defines all functions needed by Verifiers: + +- VerifySignature: Check if a signature is valid +- VerifyProof: Verify a zero-knowledge proof: signature, commitment, and/or predicate. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This is the technical portion of the RFC. Explain the design in sufficient +detail that: + +- Its interaction with other features is clear. +- It is reasonably clear how the feature would be implemented. +- Corner cases are dissected by example. +- Any new or altered interfaces should include pseudo-code. + +The section should return to the examples given in the previous section, and +explain more fully how the detailed proposal makes those examples work. + +# Drawbacks +[drawbacks]: #drawbacks + +Why should we *not* do this? + +# Rationale and alternatives +[alternatives]: #alternatives + +- Why is this design the best in the space of possible designs? +- What other designs have been considered and what is the rationale for not + choosing them? +- What is the impact of not doing this? +- For incorporating new protocol implementations what other implementations + exist and why were they not selected? +- For new protocols, what related protocols exist and why do the not satisfy + requirements? + +# Prior art +[prior-art]: #prior-art + +Discuss prior art, both the good and the bad, in relation to this proposal. +A few examples of what this can include are: + +- For other teams: What lessons can we learn from what other communities have + done here? +- Papers: Are there any published papers or great posts that discuss this? If + you have some relevant papers to refer to, this can serve as a more detailed + theoretical background. + +This section is intended to encourage you as an author to think about the +lessons from other distributed ledgers or cryptographic libraries and provide +readers of your RFC with a fuller picture. + +# Unresolved questions +[unresolved]: #unresolved-questions + +- What parts of the design do you expect to resolve through the RFC process + before this gets merged? +- What parts of the design do you expect to resolve through the implementation + of this feature before stabilization? +- What related issues do you consider out of scope for this RFC that could be + addressed in the future independently of the solution that comes out of this + RFC? + +# Changelog +[changelog]: #changelog + +- [10 Jan 2019] - v2 - a one-line summary of the changes in this version. From e659ffbd20fd94d48eb20e7d90d26633ae88fd20 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Tue, 16 Jun 2020 09:13:36 -0600 Subject: [PATCH 7/7] Initial draft Signed-off-by: Michael Lodder --- text/0002-zmix-api/README.md | 119 ++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 38 deletions(-) diff --git a/text/0002-zmix-api/README.md b/text/0002-zmix-api/README.md index 142a68e..dcb994d 100644 --- a/text/0002-zmix-api/README.md +++ b/text/0002-zmix-api/README.md @@ -20,6 +20,15 @@ criteria for issuance, credential validity periods, and revocation registries if Ursa is beginning to have many primitives that serve to construct a la carte zero-knowledge methods. Unfortunately, there hasn't been a project plan until now for organizing and layering these primitives together. +There are two ways this can be done in Rust: feature flags or subprojects. Feature flags alone become complicated +as projects grow confusing end consumers. Subprojects are great for organizing common features and code but +lines become blurred when common features surface. Zmix will use the best of both worlds. Similar to other rust projects, +Zmix will subdivide primitives into subprojects and provide a top level API for easy consumption like Serde, Rand, and Rayon. + +Serde provides a top level API that supports the common features used for serializing and deserializing data in Rust. +The exact encodings are domain specific and left up to the end user, but included in projects by specifying either features +in serde or including subprojects. Zmix will be organized in a similar way. + # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -74,62 +83,96 @@ Verifiers validate received proofs and signatures. This RFC defines all function # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -This is the technical portion of the RFC. Explain the design in sufficient -detail that: - -- Its interaction with other features is clear. -- It is reasonably clear how the feature would be implemented. -- Corner cases are dissected by example. -- Any new or altered interfaces should include pseudo-code. - -The section should return to the examples given in the previous section, and -explain more fully how the detailed proposal makes those examples work. +Zmix defines the common top layer for issuers, holders, verifiers and any other common methods used by all roles and +zero-knowledge proof primitives. Each subcrate will hold only one primitive and all functionality associated therein. + +Below is the proposed structure + +``` +libzmix + | + --- zmix_common + | + --- utils + errors + zmix_signatures + | + --- bbs + ps + cl + cdlnt + zmix_accumulators + | + --- rsa + hyperelliptic + cks + merkle + zmix_predicates + | + --- bulletproofs + snarks + r1cs + zmix_core + | + --- issuer + holder + verifier + Cargo.toml +``` + +`common` is used for traits and logic shared across 2 or more subcrates. + +`core` is organized according to the three roles of the zero-knowledge protocols. + +`signatures` are signatures that can be used to generate signature proofs of knowledge with selective disclosure proofs. +Current signatures known to support this scheme are [BBS+](https://crypto.stanford.edu/~xb/crypto04a/groupsigs.pdf), [CL](https://groups.csail.mit.edu/cis/pubs/lysyanskaya/cl02b.pdfhttps://groups.csail.mit.edu/cis/pubs/lysyanskaya/cl02b.pdf), +[PS](https://eprint.iacr.org/2015/525.pdf), [CDLNT](https://eprint.iacr.org/2020/016.pdf), and [delegatable credentials](https://acmccs.github.io/papers/p683-camenischA.pdf). There will be common code shared among signatures +like interfaces and errors. + +`accumulators` are used for zero-knowledge set memberships. Current known schemes are accumulators of unknown order like +[RSA](https://eprint.iacr.org/2018/1188.pdf) and [Hyperelliptic Curves](https://eprint.iacr.org/2020/196.pdf), Elliptic Curve based like [CKS](https://link.springer.com/content/pdf/10.1007%2F978-3-642-00468-1_27.pdf), and [Merkle Tree](https://eprint.iacr.org/2019/1255.pdf) based. + +`predicates` are proofs for testing ranges and inequalities of [numeric](https://eprint.iacr.org/2017/1066.pdf) inputs or + other miscellaneous circuit based proofs like [PLONK](https://eprint.iacr.org/2019/953.pdf) or [SPARTAN](https://eprint.iacr.org/2019/550.pdf) and + [Verifiable Encryption](https://www.shoup.net/papers/verenc.pdf) # Drawbacks [drawbacks]: #drawbacks -Why should we *not* do this? +Creating the initial interfaces and APIs will be challenging and may slow down progress. # Rationale and alternatives [alternatives]: #alternatives -- Why is this design the best in the space of possible designs? -- What other designs have been considered and what is the rationale for not - choosing them? -- What is the impact of not doing this? -- For incorporating new protocol implementations what other implementations - exist and why were they not selected? -- For new protocols, what related protocols exist and why do the not satisfy - requirements? +The project could be organized by rust features alone. This has multiple drawbacks: cfg syntax sprinkled throughout the code, +lots of combinations in Cargo.toml, and difficult to keep in mind all the various features when adding or modifying code. This makes +for a monolithic project that is consumable by users but requires documenting all features and complex combinations and coding +for dangerous combinations. + +The project could be organized by just subcrates with no common API and consumers could pick and choose each one to use. +The disadvantage is code duplication across projects. # Prior art [prior-art]: #prior-art -Discuss prior art, both the good and the bad, in relation to this proposal. -A few examples of what this can include are: +## Good examples -- For other teams: What lessons can we learn from what other communities have - done here? -- Papers: Are there any published papers or great posts that discuss this? If - you have some relevant papers to refer to, this can serve as a more detailed - theoretical background. +[Rand](https://github.com/rust-random/rand) -This section is intended to encourage you as an author to think about the -lessons from other distributed ledgers or cryptographic libraries and provide -readers of your RFC with a fuller picture. +[Crossbeam](https://github.com/crossbeam-rs/crossbeam) + +[RustCrypto Hashes](https://github.com/RustCrypto/hashes) + +[RustCrypto Encryption](https://github.com/RustCrypto/traits) + +## Bad examples + +[libursa](https://github.com/hyperledger/ursa/blob/master/libursa/Cargo.toml) # Unresolved questions [unresolved]: #unresolved-questions -- What parts of the design do you expect to resolve through the RFC process - before this gets merged? -- What parts of the design do you expect to resolve through the implementation - of this feature before stabilization? -- What related issues do you consider out of scope for this RFC that could be - addressed in the future independently of the solution that comes out of this - RFC? - # Changelog [changelog]: #changelog -- [10 Jan 2019] - v2 - a one-line summary of the changes in this version. +- [15 Jun 2020] - v1 - Initial draft