diff --git a/README.md b/README.md index 2ac517436..0f76cf230 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Changes to the protocol specification and standards are called NEAR Enhancement | [0452](https://github.com/near/NEPs/blob/master/neps/nep-0452.md) | Linkdrop Standard | @benkurrek @miyachi | Final | | [0455](https://github.com/near/NEPs/blob/master/neps/nep-0455.md) | Parameter Compute Costs | @akashin @jakmeier | Final | | [0514](https://github.com/near/NEPs/blob/master/neps/nep-0514.md) | Fewer Block Producer Seats in `testnet` | @nikurt | Final | +| [0529](https://github.com/near/NEPs/blob/master/neps/nep-0529.md) | Rich Online Digital Tokens spec | @cableguard | Draft | ## Specification diff --git a/neps/nep-0529.md b/neps/nep-0529.md new file mode 100644 index 000000000..a9543c873 --- /dev/null +++ b/neps/nep-0529.md @@ -0,0 +1,322 @@ +--- +NEP: 529 +Title: Rich Online Digital Tokens +Authors: Vicente Aceituno Canal +Status: Draft +DiscussionsTo: https://github.com/nearprotocol/neps/pull/529 +Type: Extensible Non fungible token (Rich Online Digital Token) akin to digital certificates +Version: 1.0.0 +Created: 2024-06-21 +LastUpdated: 2024-06-21 +--- + +## Summary + +Properly designed custom non-fungible-tokens (RODiT) can complement or replace digital certificates for most purposes. The design presented in this NEP can be easily extended for any number of use cases that use digital certificates. among them, mutual authentication, electronic mail, digital signing, code signing and time stamping. + +## Motivation + +Public Key Infrastructure is a prevalent way to use public key encryption. The original motivation of this NEP proposal are the many flaws in Public Key Infrastructure. It is beyond the scope of this NEP to explain these flaws in detail, please refer to the sources \[1\]\[2\]\[3\]\[4\]. + +Using blockchain issued tokens equivalent to digital certificates can provide better functionality than traditional digital certificates without compromising security. + +Currently there are no other NEP specifications covering this specific use case. + +Problems solved + +--------------- + +In this document we call the custom non-fungible-tokens used Rich Online Digital Tokens (RODiT for short). The problems solved are the following: + +1. When implementing mutual authentication with X.509 digital certificates, the workflow has several steps, one of them requires transferring a file (CSR) between the endpoint and the CA. When using SSH digital certificates, the workflow has several steps, one of them requires registering the trusted public key in a registry of authorized keys. With RODiT we use a workflow with fewer steps, without file transfer, that is completed when the RODiT is sent (not installed), to a blockchain address. The impact of using a simpler process becomes highly significant as the number of participant endpoints grows. +2. With X.509 digital certificates, key rotation requires coordinated issuing and installing of new digital certificates when the key is due to be rotated, regardless of the expiration date of the service being secured with the digital certificate. SSH digital certificates expiration also require coordination across endpoints. With RODiT, key rotation is decoupled from service expiration, as it does not require issuing a new RODiT. Key rotation using RODiT can be performed independently for every endpoint, without any coordination between the parties, greatly simplifying the management of key rotation. +3. Rogue Certificate Authorities (Issuers in X.509 terminology) can generate digital certificates to any identifier, despite of Certificate Transparency and CAA records, making key pinning necessary in high security scenarios. Any X.509 Issuer can create a digital certificate for any domain name, while the legitimate owner of the domain name may not be aware it has been issued. While RODiT are based on smart contracts controlled by Issuers, it is the Service Providers that issue and revoke RODiT for the identifiers they control, and the Service Provider has the exclusive prerogative to authorize the smart contract. This prevents Unexpected Certificates as described in \[5\], making key pinning or Certificate Transparency unnecessary. This NEP describes a mechanism for domain names use by service providers to declare what Issuers are trusted to issue valid digital certificates for them, removing this threat. + +Potential use cases + +-------------------; + +Rich Online Digital Tokens can be used as a complement or replacement of digital certificates for VPN authentication (reference implementation at [https://github.com/cableguard]), SSH authentication and API authentication, among others.NEPs + +## Scope + +This NEP includes RODiT structure with mandatory and optional fields. It does not include: + +* Governance of RODiT, who can create RODiT issuing smart contracts and how is their reputation determined. +* How RODiT field values are validated to be accurate, particularly when a field is an identifier or an address. +* How wallets interact via IPC or other mechanisms with applications using RODiT. + +## Terminology + +Some terms are used with a specific meaning, as follows: + +* **Rich Online Digital Token**: Abbreviated as RODiT, is a non fungible token which lifecycle and structure is conformant with this document. +* **Service Provider**: Organization that signs its RODiT digitally and provides a service to users where RODiT are used for mutual authentication. +* **Issuer**: The organization that creates a smart contract that is used by the Service Providers to mint their RODiT. +* **Holder**: A person or system that controls a RODiT via a key pair in a cryptographic wallet. + +## Specification + +An implementing contract MUST include the following fields on-chain: + +| **Field Name** | **Description** | **X.509 Equivalent** | **Type and Format** | **Default value and Valid Range** | +| --- | --- | --- | --- | --- | +| **versionnumber** (**NFT\_METADATA\_SPEC**) | Version Number that indicates that a the contract adheres to the current versions of this spec. This will allow consumers of the Non-Fungible Token to know if they support the features of a given contract. | Version Number | String | RODiT-near.org-MM.nn.rr , MM: Major version , nn: Minor version , rr: revision , where M, m and r are decimal digits. | +| **symbol** | Symbol | Not Applicable | String | default value when implementing this standard without custom fields: RODiT | +| **base\_uri** | Smart Contract ID, serves as identification of the Issuer | Issuer Unique Identifier | URL to guarantee it is unique and controlled by a single entity | URL | +| **NFT\_STANDARD\_NAME** | Smart Contract Standard | No equivalent | String | NEP509 | + +For sample implementation see: [https://github.com/cableguard/cgforge/blob/mainnet/contract/src/metadata.ts] + +Note: + +* MODIFIEDBASE\_URI is base\_uri, replacing the dot separating the TLD with the rest of the domain name with a dash “-”. +* SMARTCONTRACTID follows the following format: MMNNrr-MODIFIEDBASE\_URI.org + +An implementing Rich Online Digital Token MUST include the following fields on-chain: + +| **Field Name** | **Description** | **X.509 Equivalent** | **Type and Format** | **Default value and Valid Range** | +| --- | --- | --- | --- | --- | +| **token\_id** | Unique ID of the token, must be randomly generated | Serial Number | String | For Service Provider is a String like SMARTCONTRACTID;id=ULIDOFTHESERVICEPROVIDER, For Node is a String like: id=ULID | +| **issuer\_name** | Your Service Provider Name | Issuer Name | String | No default value / IT CAN BE EMPTY | +| **description\_rodit** | Description of your Service Provider | Not Applicable | String | No default value / IT CAN BE EMPTY | +| **not\_after** | Date of Expiration of Service | Not After | ISO 8601 YYYY/MM/DD | Default value one year from today’s day, must be greater than **not\_before**, and must take the value 1970/1/1 for “any” | +| **not\_before** | Date of Start of Service | Not Before | ISO 8601 YYYY/MM/DD | Default value today’s date, must take the value 1970/1/1 for “any” | +| **subjectuniqueidentifier\_url** | Service Provider URL | Subject Unique Identifier | URL to guarantee it is unique and controlled by a single entity | No default value, IT CAN NOT BE EMPTY | +| **serviceprovider\_id** | Service Provider ID | Not Applicable | String likeid=ULID or SMARTCONTRACTID;id=ULID | For Service Provider is: ULIDOFTHESERVICEPROVIDER, For Node is a String like SMARTCONTRACTID;id=ULIDOFTHESERVICEPROVIDER | +| **serviceprovider\_signature** | Ed25519 digital signature signed with the Private Key in Base58 | Certificate Signature | String of length 64 | No Default, Ed25519 digital signature (SHA384WITHECDSA), signed with the Private Key in Base58 | + +For sample implementation see: [https://github.com/cableguard/cgforge/blob/mainnet/contract/src/metadata.ts] + +The following X.509 fields are not implemented as part of RODiT by default, but practitioners may add custom fields with any information necessary for their use case: + +| **X.509** | **Description** | +| --- | --- | +| Signature Algorithm ID | EdDSA when using ed22519 compatible blockchains, , blockchain dependent | +| Subject name | URLs, DNS entries, or Email addresses | +| Subject Public Key Info | Not applicable to RODiT, blockchain dependent | +| Public Key Algorithm | EdDSA when using ed22519 compatible blockchains, blockchain dependent | +| Subject Public Key | Not applicable to RODiT, blockchain dependent | +| Certificate Signature Algorithm | EdDSA when using ed22519 compatible blockchains, blockchain dependent | + +For sample implementation of custom fields see (examples with the fields cidrblock, listenport, dns, allowedips): For sample implementation see: [https://github.com/cableguard/cgforge/blob/mainnet/contract/src/metadata.ts] + +## Interface + +Metadata applies at both the contract level (`RoditContractMetadata`) and the token level (`TokenMetadata`). The relevant metadata for each: + +```java +export class RoditContractMetadata = { + versionnumber: string; + name: string; + symbol: string; + issueruniqueidentifierURL?: string; +} + +export class TokenMetadata { + issuername?: string; // Provider of the VPN Service + description?: string; // Description of the VPN Service + notafter?: string; // When the VPN Service expires, Unix epoch in milliseconds, 1 year by default in the user interface + notbefore?: string; // When the VPN Service starts, Unix epoch in milliseconds + subjectuniqueidentifierurl?: string; // Intial URL where the clients connect + serviceproviderid?: string; // Non fungible token ID of the "author" of the set of Non fungible tokens created + serviceprovidersignature?: string; // Hash of the Non fungible token signed with serviceproviderid's publickey sourced from the blockchain +} +``` + +Service Provider root RODiT format + +---------------------------; + +| **Field Name** | **Default value and Valid Range** | +| --- | --- | +| **token\_id** | SMARTCONTRACTID;id=ULIDOFTHESERVICEPROVIDER | +| **issuer\_name** | Service Provider issuer\_name | +| **description\_rodit** | Service Provider description\_rodit | +| **not\_after** | expiration date | +| **not\_before** | start date | +| **subjectuniqueidentifier\_url** | url of the Service Provider | +| **serviceprovider\_id** | ULIDOFTHESERVICEPROVIDER | +| **serviceprovider\_signature** | SHA384WITHECDSA signature of the token\_id with private key of the blockchain address where the Service Provider root RODiT (this RODiT) is sent upon creation | + +Service Provider server and client RODiT format + +----------------------------------------; + +| **Field Name** | **Default value and Valid Range** | +| --- | --- | +| **token\_id** | id=ULID | +| **issuer\_name** | Service Provider issuer\_name | +| **description\_rodit** | Service Provider description\_rodit | +| **not\_after** | expiration date | +| **not\_before** | start date | +| **subjectuniqueidentifier\_url** | No default value | +| **serviceprovider\_id** | SMARTCONTRACTID;id=ULIDOFTHESERVICEPROVIDER | +| **serviceprovider\_signature** | SHA384WITHECDSA signature of the token\_id with private key of the blockchain address where the Service Provider root RODiT was sent upon creation | + + +Handling of RODiT + +-----------------; + +The reference implementation of RODiT uses implicit accounts ([https://docs.near.org/integrator/implicit-accounts](https://docs.near.org/integrator/implicit-accounts) ). Upon creation, RODiT can be sent to final addresses or to an address from where RODiT can be distributed to final endpoint addresses. Practitioners can use NEAR CLI or NEAR CLI RS to view the content of a RODiT or send it to an address. The reference implementation uses a bash script to make handling the RODiT sets more user friendly. It can be found here: [https://github.com/cableguard/cgroditvpn](https://github.com/cableguard/cgroditvpn) + +The script has the following options: + +* cgroditwallet.sh: List of available accounts +* cgroditwallet.sh _accountID_: Lists the RODiT Ids in the account and its balance +* cgroditwallet.sh _accountID_ keys: Displays the accountID and the Private Key of the account +* cgroditwallet.sh _accountID_ roditId: Displays the indicated RODiT +* cgroditwallet.sh _fundingaccountId_ _unitializedaccountId_ init: Initializes account with 0.01 NEAR from funding acount +* cgroditwallet.sh _originaccountId_ _destinationaccountId_ roditId: Sends ROTD from origin account to destination account +* cgroditwallet.sh genaccount: Creates a new uninitialized accountID + +The key pair used for encryption can be rotated by sending the RODiT to a new address. + +Authentication with RODiT + +-------------------------; + +RODiT authentication is always mutual. The order for the checks and exchange protocol in the reference implementation uses the NOISE protocol (See [https://noiseprotocol.org/](https://noiseprotocol.org/)), as implemented in Wireguard ([https://www.wireguard.com/papers/wireguard.pdf](https://www.wireguard.com/papers/wireguard.pdf)), with the following steps: Initiation, Response and Confirmation. + +Both endpoints check that the peer can pass the following checks: + +1. Possession: The endpoint signs the token\_id (somehow equivalent to CertificateVerify in X.509) with the private key of the RODiT address, sends the token\_id and the signature to the peer. Upon reception the peer fetches from the blockchain the public key where the token\_id is, and checks the signature. (Notes: There is not certificate request as when using digital certificates) The reference implementation uses the function _pub fn verify\_hasrodit\_getit_ for this check. +2. Genuine: The endpoint fetches from the blockchain the public key where the serviceprovider\_id of the own RODiT is, and checks the serviceprovider\_signature against the peer’s RODiT token\_id and the fetched public key. The reference implementation uses the function _pub fn verify\_rodit\_isamatch_ for this check. +3. Live: The endpoint checks the current time and date against the not\_after and not\_before fields of the peer’s RODiT. The reference implementation uses the function _pub fn verify\_rodit\_islive_ for this check. +4. Active: The endpoint checks if there is a DNS entry using the peer’s RODiT token\_id that follows the format _token\_id.revoked.subjectuniqueidentifierurl_. If the entry exists, the RODiT has been revoked. The reference implementation uses the function _pub fn verify\_rodit\_isactive_ for this check. +5. Legitimate: The endpoint checks if the Issuer is legitimate, in other words, if it has been authorized by the Service Provider to issue RODiT for its subjectuniqueidentifierurl, by checking if there is a DNS entry using the peer’s RODiT token\_id that follows the format _SMARTCONTRACTID.smartcontract.subjectuniqueidentifierurl_. If the entry does not exists, the smart contract has been revoked. The reference implementation uses the function _pub fn verify\_rodit\_smartcontract\_istrusted_ for this check. (Note: Do we need to check if the RODiT root is Live and Active) +6. Valid: The endpoint may check optional properties of the RODiT, like location, number of transactions per minute, among other use cases. + +Reference Implementation - Minimum Viable Interface + +---------------------------------------------------; + +https://github.com/cableguard/cgtun/blob/49d01c29c656e2f34c6dc2bca67e375f9bbf8f09/cableguard/src/noise/mod.rs#L1166 + +pub fn verify_hasrodit_getit( + rodit_id: [u8;RODIT_ID_SZ], + rodit_id_signature: [u8;RODIT_ID_SIGNATURE_SZ], + +pub fn verify_rodit_isamatch( + own_serviceproviderid: String, + peer_serviceprovidersignature: String, + peer_token_id: [u8;RODIT_ID_SZ], + +pub fn verify_rodit_islive( + peer_rodit_notafter: String, + peer_rodit_notbefore: String, + +pub fn verify_rodit_isactive( + token_id: String, + own_subjectuniqueidentifierurl: String, + +pub fn verify_rodit_smartcontract_istrusted( + own_subjectuniqueidentifierurl: String, + +Security Implications + +---------------------; + +RODiT offer robust security features, including: + +* Mutual authentication by default. +* Explicit authorization of Issuers preventing man in the middle attacks. +* Easy detection and recovery from key compromise. As the RODiT is associated with a blockchain address, the only way the attacker can keep exclusive control of the RODiT is moving it to a new address. This can be observed publicly as soon as it happens. Besides, as RODiT can only be verified online, so all parties will react immediately to the RODiT being revoked an will not accept it. Man in the middle attacks are far more challenging using RODiT than X.509 certificates, as we can verify validity against multiple RPC providers or even have our own local NEAR node. + +Alternatives + +------------; + +RODiT have been developed as an alternative to X.509 and SSH digital certificates. + +Future possibilities + +--------------------; + +* RODiT could be used for SSH authentication and API authentication. +* Using RODiT can lead to new commercialization practices by Service Providers as they can delegate sales and distribution to third parties and resellers easily, by providing stocks of RODiT. + +RODiT could be used as personal user accounts not connected to any directory, with fields like: + +* **locationofbirth**: Place of birth in plus code format +* **dateandtimeofbirth**: Date and time of birth in GeneralizedTime format or RFC3339 +* **namesshared**: Part of the full name shared with family (this is known as surname in some countries) +* **namesnotshared**: Part of the full name not shared with family (this is known as name in some countries) +* **taxresidence**: Tax residence as a ISO 3166-1 alpha2-2 country code +* **taxpayercode**: Tax payer code +* **phonenumber**: Contact phone number +* **postaddress**: Contact address in plus code format + +Consequences + +------------; + +### Positive + +* Reducing complexity and costs by consolidating authentication, configuration, and licensing of online services into a single token +* Preventing rogue credential issuers through a verifiable trust model +* Enabling seamless issuing and secure delivery of credentials to endpoints +* Allowing independent key rotation decoupled from license expiration +* Robust mutual authentication and protection against man-in-the-middle attacks + +### Negative + +* The current implementation does not include mechanism to encrypt the information stored in the RODiT, so it can only store information that can be made public without consequence. + +### Backwards Compatibility + +There is no need to backwards compatibility as RODiT have a use case fundamentally different from Non-fungible tokens. + +Unresolved Issues (Optional) + +----------------------------; + +RODiT use implicit accounts at the moment due to cryptographic wallets missing any kind of interface with other software, for example browsers. The utility of RODiT will be limited to use cases that are compatible with implicit accounts until an interface is developed. + +Changelog + +---------; + +Version 1.0.0 Submitted for approval + +References + +----------; + +1. [https://www.schneier.com/wp-content/uploads/2016/02/paper-pki.pdf](https://www.schneier.com/wp-content/uploads/2016/02/paper-pki.pdf) + +2. [https://datatracker.ietf.org/doc/html/draft-housley-web-pki-problems-00.txt](https://datatracker.ietf.org/doc/html/draft-housley-web-pki-problems-00.txt) + +3. [https://www.iang.org/ssl/pki\_considered\_harmful.html](https://www.iang.org/ssl/pki_considered_harmful.html) + +4. [https://sslmate.com/resources/certificate\_authority\_failures](https://sslmate.com/resources/certificate_authority_failures) + +5. [https://datatracker.ietf.org/doc/html/draft-housley-web-pki-problems-00](https://datatracker.ietf.org/doc/html/draft-housley-web-pki-problems-00) + + +### 1.0.0 - Initial Version + +> Placeholder for the context about when and who approved this NEP version. + +#### Benefits + +> List of benefits filled by the Subject Matter Experts while reviewing this version: + +* Benefit 1 +* Benefit 2 + +#### Concerns + +> Template for Subject Matter Experts review for this version: Status: New | Ongoing | Resolved + +| # | Concern | Resolution | Status | +| --- | --- | --- | --- | +| 1 | | | | +| 2 | | | | + +Copyright + +---------; + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).