Skip to content

Latest commit

 

History

History
305 lines (228 loc) · 13.3 KB

File metadata and controls

305 lines (228 loc) · 13.3 KB
CAP: 0051
Title: Smart Contract Host Functionality: Secp256r1 Verification
Working Group:
    Owner: Leigh McCulloch <@leighmcculloch>
    Authors: Leigh McCulloch <@leighmcculloch>
    Consulted: Graydon Hoare <@graydon>, Riad S. Wahby <@kwantam>
Status: Final
Created: 2023-01-30
Discussion: https://github.com/stellar/stellar-protocol/discussions/1435
Protocol version: 21

Simple Summary

Support secp256r1 verification in Soroban contracts via the exported host interface.

Motivation

Secp256r1, also sometimes referenced as prime256r1, p256, or ES256, is a common elliptic curve used with ECDSA. It's one of the common signature algorithms used in Webauthn, which is the standard behind passkeys available on, browsers, computers, and phones. Supporting secp256r1 natively would allow for the execution of efficient webauthn implementations where-by browsers, computers, and phones could be the signers of accounts on Stellar via Soroban's custom account interface. While it is possible to embed ECDSA secp256r1 verification into contracts on the guest side, the instruction cost of ECDSA verification is greater than the networks current maximum limits.

Goals Alignment

This CAP is aligned with the following Stellar Network Goals:

  • The Stellar Network should make it easy for developers of Stellar projects to create highly usable products

Abstract

This proposal adds one function to the Soroban environment's exported interface that accepts the parameters needed to verify a secp256r1 signature of a payload for a public key.

Specification

A new function verify_sig_ecdsa_secp256r1 with export name 3 in module c is added to the Soroban environment's exported interface.

It accepts a public key, message, and signature, and verifies that the signature was produced using the ECDSA signing algorithm with the provided message and the private key on the secp256r1 curve corresponding to the provided public key.

It returns if the signature is verified, and traps if verification fails.

The public_key parameters is a BytesObject that must have a length of 65-bytes, being the ECDSA secp256r1 public key SEC-1 encoded.

The msg_digest parameters is a BytesObject that must be a hash of the message, and must have been produced using a secure cryptographic hash function, otherwise an attacker can potentially forge signatures.

The signature parameters is a BytesObject that must have a length of 64-bytes, with the first 32-bytes being the R-value big endian integer, and the second 32-bytes being the S-value big endian integer.

The env.json in rs-soroban-env will be modified as so:

diff --git a/soroban-env-common/env.json b/soroban-env-common/env.json
index df7d5c4..d1d7760 100644
--- a/soroban-env-common/env.json
+++ b/soroban-env-common/env.json
@@ -1958,6 +1958,26 @@
           ],
           "return": "BytesObject",
           "docs": "Recovers the SEC-1-encoded ECDSA secp256k1 public key that produced a given 64-byte signature over a given 32-byte message digest, for a given recovery_id byte."
+        },
+        {
+          "export": "3",
+          "name": "verify_sig_ecdsa_secp256r1",
+          "args": [
+            {
+              "name": "public_key",
+              "type": "BytesObject"
+            },
+            {
+              "name": "msg_digest",
+              "type": "BytesObject"
+            },
+            {
+              "name": "signature",
+              "type": "BytesObject"
+            }
+          ],
+          "return": "Void",
+          "docs": "Verifies that the signature of the prehashed message using the secret key of the public key. The prehash must have been produced by a cryptographic hash function, otherwise an attacker can potentially forge signatures."
         }
       ]
     },

Design Rationale

Verify vs Recovery

The interface of the function is different to the existing ECDSA secp256k1 interface because the latter is a recovery interface that recovers a public key given a message, signature, and a recovery ID.

The secp256r1 interface is proposed as a verification interface accepting a public key, message, and signature, because the majority of existing signing software and hardware that support ECDSA secp256r1 do not provide the recovery ID.

To support a recovery interface for secp256r1 the Soroban environment could perform two recoveries, one with recovery ID 0 and again with recovery ID 1, to determine all possible matching public keys. Doing so would require two rounds of recovery and the operations and since the operations take up to 2ms each it would not be acceptable to do twice.

Alternatively, it would be possible for off-network software to take an ECDSA public key, message, and signature and derive the recovery ID by performing one to two verifications off-network. Doing so would require that all clients embed ECDSA secp256r1 recovery implementations which are not common in non-blockchain systems, such as browsers or phones implementing webauthn/passkeys.

A motivation to use the alternative recovery interfaces is that it will likely that contract that use secp256r1 verification will store a public key on chain, or communicate the public key in invocation parameters. In both cases a verification interface will require transmission and storage of the full 65-byte public key. A recovery interface would allow for hashing and truncating the transmitted or stored public key to 32-bytes if hashed with SHA-256, or 20-bytes if hashed and truncated similar to how Ethereum addresses are produced. This space reduction would lower the read/write resource usages as well as transactions size, for an increase in instruction cost.

SEC1 Encoding of Public Key

The proposal specifies the public key to be SEC1 encoded. This encoding is 65-bytes, containing the point coordinates uncompressed, and is the same encoding used by the existing recover_key_ecdsa_secp256k1 function.

Most applications using secp256r1 are likely to produce a 72-byte ASN.1 DER encoded public key, which is convertible.

Compact Encoding of Signature

The proposal specifies the signature to be encoded as two 32-bit big endian integers. This encoding is 64-bytes and is the same encoding used by the existing recover_key_ecdsa_secp256k1 function.

Most applications using secp256r1 are likely to produce a 70 to 73-byte ASN.1 DER encoded signature, which is convertible.

Webauthn / Passkeys

The secp256r1 verify interface is largely motivated by the webauthn use case. Webauthn involves an application registering with a client, that produces a private key, and provides the public key back to the application. The application can then engage the client to sign data that the application can verify using the public key shared earlier.

The client may be a browser, phone, secret manager, or other software.

The application could be a dapp, application, browser extension, or any other software.

The public key could be an EdDSA (ed25519), ES256 (ECDSA secp256r1), PS256, or RS256, where the last two are both RSA signing algorithms.

In all signing algorithms the payload to sign is produced by concatenating the webauthn authenticator data, and a SHA-256 hash of the client data JSON. The client data JSON contains several fields, one being the challenge field, that an application requesting a signature can set. The challenge provided by an application is base64 url encoded in the challenge field of the client data JSON.

For example, a client data JSON:

{
  "type":"webauthn.get",
  "challenge":"hJHFvaaoU7qkcH9kML46shLL_btpYGCA6ty3ie0M1Qw",
  "origin":"http://localhost:4507",
  "crossOrigin":false
}

For Stellar transactions intended to be authenticated by a webauthn signature in a Soroban custom account, this challenge can be the SHA-256 hash of the HashIDPreimage ENVELOPE_TYPE_SOROBAN_AUTHORIZATION.

In the ed25519 algorithm the payload as-is is passed to the signature verification function.

In the ECDSA secp256r1 algorithm the payload is hashed using SHA-256, and the hash is passed to the verification function.

It could be argued that adding secp256r1 signature verification is insufficient to implement webauthn signature verification in a contract because verification also requires JSON and base64 url support, neither of which are supported by the Soroban host functions.

There are some aspects of Webauthn that are discussed below by the proposal. Even though the concerns are not critical concerns of the proposal of secp256r1 alone, the proposals is primarily motivated by Webauthn, and the concerns below establish whether this proposal alone would be sufficient to establish a Webauthn contract on Soroban.

Base64 URL Encoding

It is possible to embed a small and efficient fixed width base64 url encoder into a contract. Therefore the lack of native base64 URL encoding in the Soroban environmen host interface is not a limiting factor. See leighmcculloch/soroban-base64.

JSON

It is possible to embed the serde-json-core crate for decoding a message. There are some limitations depending if the alloc feature of the soroban-sdk is used or not. The limitations are not prohibitive. See leighmcculloch/soroban-json.

Also, it is reasonable to take the position that the limited verification of client data JSON, which is discussed at length in the specification, means that a fully fledged JSON parser is not required.

The specification says Relying Parties (RP) should handle key reordering and new values being introduced. But the specification also goes to great length to detail how the client data json is a subset of JSON, and a limited resource parser can be written so as to verify the client data JSON.

Therefore, multilpe options exists appealing to different risk and costs appetites.

Challenge Suitability

The statements in this section must be verified.

The Webauthn specification requires that the challenge be randomized to avoid replay. The contract is the Relying Party (RP) in the authentication ceremony. Therefore the RP is supposed to select a randomly generated challenge value. However, as a contract existing on chain, this is not possible. Instead it can be stated that the challenge will be random preventing replay because the RP by requires that the challenge be a hash of the Soroban Authorization, and best practice requires that any authenticating client select a random nonce for the Soroban Authorization.

Signature Counters Utility

The statements in this section must be verified.

The Webauthn specification allows an authenticator to keep track of a signature counter and to communicate that counter to the RP via the authenticator data that is part of data that is signed.

Relying Parties (RP) are encouraged to use the signature counter as signal to whether the authenticator has been inappropriately cloned. An RP would identify that there exists a cloned authenticator by seeing the counter go backwards.

It's worth noting that an RP wouldn't be able to identify which authenticator was the cloned authenticator, and only that one existed.

If a contract detected this scenario it wouldn't be able to take any independent action such as locking the account, as it would have no way to identify which authenticator was cloned. A contract might have a backup credential that could be used to unlock it in this situation, but that is out-of-scope of this proposal.

Protocol Upgrade Transition

Backwards Incompatibilities

This proposal is completely backwards compatible.

Resource Utilization

Metering

An ECDSA secp256r1 verification takes approximately 2ms in current tests. It must be appropriately metered.

Storage

The use of a verify interface rather than a recovery interface requires that the 65-byte public key be stored or transmitted into the host for verification. It could be reasonable to present, or later add, a recovery interface that could more efficiently work with a truncated hash of the public key. See the Design Rationale section for more details.

Security

Prehash

The msg_digest parameter must be a prehash produced by a secure cryptographic hash function per the ECDSA specification. The non-specification of the hashing function by the host function could be a weakness if developers use the flexibility to build logic that produce signatures not using such a hash function, but to require the use of a specific hash function would be unreasonable as it would be unnecessarily restrictive and would require transmission of the entire message that may not be desirable for a number of reasons, such as resource cost or privacy.

Audited Implementations

The only ECDSA secp256r1 pure-Rust crates that the Soroban environment could embed are the p256 and ecdsa crates. At the date that this proposal has been written both crates have a warning in their readme indicating that they have never been independently audited.

Test Cases

None yet.

Implementation

None yet. But will be tracked by [stellar/rs-sorovan-env#807] if implemented.