Skip to content

Verified Identity with X.509 Certificates

Introduction

In STRATO, all users have verified, real-world identities associated with their machine-readable STRATO address (such as 0x89bd47cd7cf6d516c2ff0a7ca2a12ec995b00a03). This allows every user transacting on the STRATO Mercata network to audit or verify who a user is in the real world by knowing their STRATO address, or vice versa. Without this, any transactions on the blockchain are relatively anonymous. To associate user addresses with a more meaningful, auditable identity, STRATO uses X.509 certificates.

A X.509 certificate is a digital file that binds a user's identity to a public key using a digital signature, employing widely accepted cryptographic standards. This protocol is widely used for internet browser security and networking.

STRATO integrates X.509 Certificates directly on the blockchain, allowing a user's identity to be cryptographically verified and authenticated. This enables apps to use KYC functionality and participate in contracts with trusted partners.

Using the X.509 certificate protocol in STRATO allows for the following:

  • Verified identities associated with a user's STRATO address - including information such as organization, organizational unit in that organization, or country (e.g. “Acme", “Sales”, and "USA").
  • A database of address-name pairs to look up user identities by their STRATO address stored on-chain and accessible from the STRATO Cirrus API.
  • The ability to create complex contract logic in Solidity that is based on a user's identity, such as requiring someone to be part of "Acme" to execute a particular function.
  • A hierarchical structure where certificate authorities (CAs) issue organization certificates. Properly certified organizations are part of the network. The certified organizations in turn issue certificates to their users. Properly certified users are part of the organization that gave them their certificates.

Warning

As of STRATO ^8.0, all users are required to have X.509 identities before making any transactions.

Verified Identities

STRATO ensures all user identities in X.509 certificates are Verified Identities. This is accomplished by following two-key industry standards not-dissimilar to those followed by internet browsers facilitating secure HTTPS connections through SSL.

Identity Verification

No ordinary certificate can be registered into the STRATO certificate database. Instead, certificates must contain info about a user's identity that is directly verified by BlockApps or another entity with a Verified Identity. BlockApps gets the credentials from a user when they sign up to be a part of the STRATO Mercata network. After submiting the request, a user may immediately use the network, however they cannot post transactions until BlockApps has completed the identity verification process. At this time the user will receive an email that they have been verified and can fully interact with STRATO Mercata.

This process is similar to a Certificate Signing Request when obtaining an SSL certificate for a website through a Certificate Authority like Comodo SSL or GeoCert SSL. Identities that are verified indirectly by other verified entities are fully responsible for the user identification process and BlockApps cannot be responsible for malicious data contained within a certificate verified in this manner.

Since STRATO account addresses are directly linked to a user's public key (See STRATO Accounts), the certificate registration process guarantees that a certificate in the database is only registered to the address derived from the public key contained within the certificate. This way other users can be sure that a user's identity is properly associated with their STRATO account.

Obtaining a Verified Identity

Certificates are granted to users on the STRATO Mercata Network after their submitted credentials have been externally verified.

Overall the process is as follows:

  • user signs up for the STRATO Mercata network
    • Provides email and other identifying information
  • Request is submitted and user's STRATO address is generated
  • BlockApps reviews information
  • After successful verification, BlockApps registers the user's identity on-chain with a signed X.509 certificate
  • Users may now post transactions to STRATO Mercata

X.509 Certificate Basics

An X.509 Certificate is a digital record of an entity's identity. It can be thought of as a digital ID issued by an authority. It contains 4 main sections: the Subject, the Issuer, the Public Key, and the Signature. There are also fields for metadata; however, they are not relevant here.

Certificate Subject/Issuer

The subject contains information about who the certificate is for. For your ID, you are the ID's subject. The issuer contains information about who gave the certificate to the subject. For your ID, this would be like the government or your organization. An X.509 certificate contains the following fields for its subject and issuer (with abbreviated names):

  • Common Name (CN)
    • The subject's identifying common name (like "Ryan" or "Marjorie")
  • Organization (O)
    • The organization that the subject belongs to
  • Organization Unit (OU)
    • The department or sub-unit that the subject belongs to within their organization
  • Country (C)
    • The subject's country of operation/residence
  • Locality (L)
    • The subject's region of operation within their Country

A certificate that has the same subject/issuer is called "self-signed" and in most cases represents an entity that is a Certificate Authority.

Expiration Date

In addition to subject/issuer metadata, the certificate has an expiration date. This can be used in smart contract logic to determine whether a user's identity is still valid or if it should be renewed.

Certificate Public Key

The Public Key section contains information about the subject's public key. The subject must be in possession and control of the corresponding private key.

  • Key Algorithm
    • The algorithm used to generate the key
  • Key Size
    • The bit size of the key
  • Public Key
    • The DER encoded public key itself

Certificate Signature

The signature is the critical part of the certificate that enables it to be cryptographically secure and verified. Without this, there is no way to guarantee that the information in the certificate has not been falsified or tampered with. In most cases, a certificate is signed with the private key of the issuer.

  • Signature Algorithm
    • Describes the hashing and signature algorithm used to sign this certificate
  • Signature
    • The actual signature of the certificate's data

The authenticity of a certificate may be checked at any time by performing a cryptographic signature verification on the certificate hash with the issuer's public key.

Certificate Chains

The X.509 standard allows for certificate chains. This allows a valid certificate holder that is not necessarily an authority to sign and create valid certificates for other users. This allows a chain of trust to be created from the main "Trust Anchor" to the final certificate holder. In a certificate chain, the certificates of all entities must be included in the certificate bundle. So a certificate may be 1 or more individual certificates contained within a single file. This way, another party that requests and verifies the certificate always has the required information to identify an entity.

Certificate chain example:

-----BEGIN CERTIFICATE-----
MIIBgzCCASegAwIBAgIQJN1cZoLJ4yhjGrEHRxzPNDAMBggqhkjOPQQDAgUAMEMx
DjAMBgNVBAMMBUNOT25lMREwDwYDVQQKDAhDTk9uZU9yZzEQMA4GA1UECwwHT25l
VW5pdDEMMAoGA1UEBgwDVVNBMB4XDTIyMDUxMDE5MTcwMloXDTIzMDUxMDE5MTcw
MlowQzEOMAwGA1UEAwwFQ05Ud28xETAPBgNVBAoMCENOVHdvT3JnMRAwDgYDVQQL
DAdUd29Vbml0MQwwCgYDVQQGDANVU0EwVjAQBgcqhkjOPQIBBgUrgQQACgNCAATk
iocODuRYeg5AZT80BwIAdH+ScbFdsUG9xhjOfG82c4TeuCMsoUslu4JsvL6MfaV8
U7l8Lw0M6yiTGb0DPveZMAwGCCqGSM49BAMCBQADSAAwRQIhAKr7MLKSXJ1bOpGO
fbLV+n+dzQjd2gQXXqP0OMIIDjuGAiBaeadbSMOTJRYIJ4PV9C0oyyk/Xrvv4/R/
Eyun8du+BQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBiTCCAS2gAwIBAgIRAN7G0Wzu8Z4GkKgUUNkz4kEwDAYIKoZIzj0EAwIFADBI
MQ4wDAYDVQQDDAVBZG1pbjESMBAGA1UECgwJQmxvY2tBcHBzMRQwEgYDVQQLDAtF
bmdpbmVlcmluZzEMMAoGA1UEBgwDVVNBMB4XDTIyMDUxMDE5MTY1OVoXDTIzMDUx
MDE5MTY1OVowQzEOMAwGA1UEAwwFQ05PbmUxETAPBgNVBAoMCENOT25lT3JnMRAw
DgYDVQQLDAdPbmVVbml0MQwwCgYDVQQGDANVU0EwVjAQBgcqhkjOPQIBBgUrgQQA
CgNCAARaBoYAP4TNHMD7Nkgs8PNHMMmJRF9Nhhn89iPHbppw4AooeNfoeQ1SVWAn
Q3/Wh4w9hGFeba0MaBm3pVtLWJ/zMAwGCCqGSM49BAMCBQADSAAwRQIhAPmPkkFv
5nGnvprxgxOqW9xQiuCdTzBSTGELvlzwe2CIAiBFjj1qyTywdRej7fSOfG9il421
dB2DWeHbCK7C6S6PvQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBjTCCATKgAwIBAgIRAOPPkVoBp/GnwZGR32jcIjwwDAYIKoZIzj0EAwIFADBI
MQ4wDAYDVQQDDAVBZG1pbjESMBAGA1UECgwJQmxvY2tBcHBzMRQwEgYDVQQLDAtF
bmdpbmVlcmluZzEMMAoGA1UEBgwDVVNBMB4XDTIyMDQyMDE3NTcxM1oXDTIzMDQy
MDE3NTcxM1owSDEOMAwGA1UEAwwFQWRtaW4xEjAQBgNVBAoMCUJsb2NrQXBwczEU
MBIGA1UECwwLRW5naW5lZXJpbmcxDDAKBgNVBAYMA1VTQTBWMBAGByqGSM49AgEG
BSuBBAAKA0IABFISUeMfsGYl/sWStpv6cDeNHLwktFAO2dAwe7J8uWZzS8ONyYCs
9FEQ2NsmDj5IaCAKcRSvVFNwXOAUQDQ1pnUwDAYIKoZIzj0EAwIFAANHADBEAiA8
R0UERQZbF3qJUt5A0ZFf2ZmB0l/ZPjIvM383gOF3xwIgbxbQ8NLkDEe2mWJ/qa4n
N8txKc8G9R27ZYAUuz15zF0=
-----END CERTIFICATE-----

In this certificate chain, the first certificate is the target certificate, the middle certificate is an intermediate certificate, and the last certificate is called the certificate anchor. A certificate chain is a list, the first cert is signed by the second, and the second cert is signed by the last one. For example, the cert anchor would be a CA, the intermediate cert would be an organization on the network, and the target cert would be a user within the organization of the intermediate cert.

We recommend this informative video on X.509 Certificates that explains the technology in-depth. Further discussion can be found in this Wikipedia article.

Cryptographic Integrity

Certificates registered on STRATO networks are checked for their cryptographic authenticity to ensure an authority has issued the certificate. This is done through ECDSA signature verification on the data contained within the certificate. If the signature is not valid, then the certificate cannot be registered onto the blockchain.

Aside from the certificate authorities on the network, X.509 certificates are linked together to create what are known as certificate chains. A chain of certificates numbered [0... N] are valid if they meet the following criteria:

For each cert k in [0... N-1]:

  1. The issuer of cert k is the subject of cert k + 1
  2. The signature of cert k is verified by the public key of the subject in cert k + 1

Certificate N (the root cert) must be signed by a valid certificate authority (CA).

See the Official X.509 Certificate Chaining Rules for the formal details.

Certificate chaining allows organizations to possess and register a single certificate signed by a CA, and subsequently issue as many certificates to their users as needed.

Certificate Authorities

At the time of writing, the sole STRATO Certificate Authority is BlockApps Inc, which has the following self-signed certificate and corresponding public key (DER encoded, PEM format):

-----BEGIN CERTIFICATE-----
MIIBjTCCATKgAwIBAgIRAOPPkVoBp/GnwZGR32jcIjwwDAYIKoZIzj0EAwIFADBI
MQ4wDAYDVQQDDAVBZG1pbjESMBAGA1UECgwJQmxvY2tBcHBzMRQwEgYDVQQLDAtF
bmdpbmVlcmluZzEMMAoGA1UEBgwDVVNBMB4XDTIyMDQyMDE3NTcxM1oXDTIzMDQy
MDE3NTcxM1owSDEOMAwGA1UEAwwFQWRtaW4xEjAQBgNVBAoMCUJsb2NrQXBwczEU
MBIGA1UECwwLRW5naW5lZXJpbmcxDDAKBgNVBAYMA1VTQTBWMBAGByqGSM49AgEG
BSuBBAAKA0IABFISUeMfsGYl/sWStpv6cDeNHLwktFAO2dAwe7J8uWZzS8ONyYCs
9FEQ2NsmDj5IaCAKcRSvVFNwXOAUQDQ1pnUwDAYIKoZIzj0EAwIFAANHADBEAiA8
R0UERQZbF3qJUt5A0ZFf2ZmB0l/ZPjIvM383gOF3xwIgbxbQ8NLkDEe2mWJ/qa4n
N8txKc8G9R27ZYAUuz15zF0=
-----END CERTIFICATE-----

Any X.509 certificate can be verified against the following BlockApps root public-key (DER encoded, PEM format):

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEUhJR4x+wZiX+xZK2m/pwN40cvCS0UA7Z
0DB7sny5ZnNLw43JgKz0URDY2yYOPkhoIApxFK9UU3Bc4BRANDWmdQ==
-----END PUBLIC KEY-----

Accessing Verified Identities

Certificates in SolidVM

Using the CertificateRegistry Dapp

To obtain information about a user's X.509 certificate registered through the CertificateRegistry Dapp, the CRA exposes the following function, which can be referenced in other smart contracts so the entire Certificate Smart Contract information can accessed directly within the VM.

Function Signature:

function getUserCert(address _address) returns (address);

This function will return the Certificate contract address of user's address passed through the _address parameter. If no such certificate exists, it will return the 0 address. After getting address of the Certificate it should be cast as a Certificate type in the contract so that its members and functions are fully accessible.

Example

import "/CertificateRegistry.sol"

contract UseCRAIdentity {

  CertificateRegistry cra;
  Certificate         contractOwner;

  constructor(address _craAddress) {
    cra = CertificateRegistry(_craAddress, "main");
    contractOwner = cra.getUserCert(tx.origin);
  }
}

Using SolidVM built-in

To obtain information about a user's X.509 certificate, SolidVM 3.0; 3.2 have a built-in function getUserCert. This can be used to get the identity information of a user based on their STRATO address.

getUserCert function signature:

function getUserCert(account _account) returns (mapping(string => string));

The function returns the subject information for this user's certificate as key/values:

  • commonName
    • The account's registered Common Name (CN)
  • organization
    • The account's registered Organization (O)
  • organizationalUnit
    • The account's registered Organizational Unit (OU)
  • country
    • The account's registered Country (C)
  • publicKey
    • The account's registered Public Key
    • DER encoded
    • This is identical to the account's public key in STRATO's Vault
  • certString
    • The DER encoded string of the user's X.509 certificate
  • expirationDate
    • The Unix timestamp of the expiration of the certificate and can be parsed as an int to be used in mathematical contexts.

If an account does not have an identity on STRATO, the function will return a mapping with empty values for each key.

pragma solidvm 3.2;
contract IdentityFetcher {

  constructor() {}

  function getIdentity(address _addr) returns (string, string, string, string, string, string, int) {
    account myAccount = account(_addr, "main");
    string myCommonName   = getUserCert(myAccount)["commonName"];      // Get the common name
    string myCountry      = getUserCert(myAccount)["country"];         // Get the country
    string myOrganization = getUserCert(myAccount)["organization"];    // Get the organization
    string myorganizationalUnit = getUserCert(myAccount)["organizationalUnit"];  // Get the organizationalUnit
    string myPublicKey    = getUserCert(myAccount)["publicKey"];       // Get the public-key
    string myCertificate  = getUserCert(myAccount)["certString"];      // Get the cert string
    int certExpirationDate = int(getUserCert(myAccount)["expirationDate"], 10); // Get the cert expirationDate
    return (myCommonName, myCountry, myOrganization, myOrganizationalUnit, myPublicKey, myCertificate, certExpirationDate);
  }
}

BlockApps Public Certificate Registry

When a user's certificate is registered on STRATO, their identity information is put in the STRATO Certificate Registry List, the database of contracts representing all Verified Identities on the network.

For reference, the Certificate contract contains the following relevant public state variables:

  • userAddress : address
    • The address of the user that this cert belongs to.
  • parent : address
    • The address of this Certificate's parent in the Certificate chain.
  • children : address[]
    • The array of children Certificates that have been issued by this certificate.
  • commonName : string
    • The Subject Common Name of this Certificate.
  • country : string
    • The Subject Country of this Certificate.
  • organization : string
    • The Subject Organization of this Certificate.
  • organizationalUnit : string
    • The Subject Organizational Unit of this Certificate.
  • group : string
    • The Subject Organizational Unit of this Certificate (prefer organizationalUnit field.)
  • publicKey : string
    • The Subject Public Key of this Certificate.
  • certificateString : string
    • The raw PEM encoded X.509 Certificate string.
  • isValid : bool
    • Whether or not this Certificate has been revoked by any ancestor Certificate.
  • expirationDate : uint
    • The Unix Timestamp of this Certificate's expiration date.

User's may access this by querying the Cirrus API for the Certificate table:

Request:

curl -X GET \
-H "Authorization: Bearer <token>" \
-H "Accept: application/json" \
"https://<strato_address>/cirrus/search/Certificate"

Response:

[
  {
    "userAddress": "1471df2240030205327A8D2F438c60ba4AE97355", 
    "commonName": "Rebekah",
    "organization": "Standard Oil",
    "organizationalUnit": "Product",
    "country": "USA",
    "publicKey": "<public-key>",
    "certString": "<certificate>",
    "expirationDate": "<expiration-date>",
  },
  ...
]
const contract = {
  name: "Certificate"
}

const rows = await rest.search(stratoUser, contract, options)

Response:

const rows = [
  {
    userAddress: "1471df2240030205327A8D2F438c60ba4AE97355", 
    commonName: "Rebekah",
    organization: "Standard Oil",
    organizationalUnit: "Product",
    country: "USA",
    publicKey: "<public-key>",
    certString: "<certificate>",
    expirationDate: "<expiration-date>",
  },
  ...
]

Using Verified Identities

Once a user has an identity, this allows them to make transactions on the Mercata network and enables useful STRATO features like Cirrus Table namespacing based on Organization, and built-in tx identity properties.

Warning

In SolidVM 3.3 / STRATO 7.7 - 7.9, SolidVM built-ins are no longer available to access an address' verified identity registered with the Certificate Registry Dapp. Identities registered in SolidVM 3.0 or 3.2 are still accessible from the SolidVM built-ins. Compatibility is listed next to each feature. In STRATO ^8.0 users may access identities through either the SolidVM built-in OR the Certificate Registry Dapp public function.

Transaction Built-in Properties

Requirements: SolidVM 3.0; 3.2 OR STRATO 8.0.

Any transaction posted by a user with a Certificate will extend the built-in tx member to contain the following properties:

  • tx.username
    • The transaction origin's registered Common Name (CN)
  • tx.organization
    • The transaction origin's registered Organization (O)
  • tx.organizationalUnit
    • The transaction origin's registered Organizational Unit (OU)
  • tx.certificate
    • The transaction origin's registered raw Certificate string

If there is no identity of the transaction's origin, then each property will default to the empty string.

Identity-Based Table Namespacing

Requirements: SolidVM 3.0; 3.2 OR STRATO 8.0.

When a user with an identity posts a smart contract, the contract will automatically be associated with their organization and/or smart contract application in the Cirrus database. This allows for multiple organizations to create contracts with similar names, avoiding naming collisions or confusion in the database.

Contracts created by users with identities will have their organization name prefixed with the contract name in the Cirrus database. For example, if users from BlockApps and an associated company, Standard Oil, both post an "Asset" contract on the same network, then Cirrus will store each contract in separate tables - one for BlockApps-Asset and one for StandardOil-Asset. This means data from the StandardOil's Asset will be kept separate from the data of BlockApps' Asset. Any version changes to either contract will be kept in a separate table in the database.

A look at the schema inside the Cirrus database would look something like this:

                List of relations
 Schema |       Name                                    |   Type    |  Owner   
--------+-----------------------------------------------+-----------+----------
 public | StandardOil-Asset                             | table     | postgres
 public | BlockApps-Asset                               | table     | postgres
 public | BlockApps-AssetFactory-Asset                  | table     | postgres

App-Name Table Prefixing

Contracts created from other contracts using the new keyword (commonly called the factory or manager pattern) will be prefixed by the name of the creator contract. This is only enabled for contracts created by users with identities.

If BlockApps uses AssetFactory to create Asset, the cirrus table name for the Asset contract would be BlockApps-AssetFactory-Asset.

                List of relations
 Schema |       Name                                    |   Type    |  Owner   
--------+-----------------------------------------------+-----------+----------
 public | BlockApps-AssetFactory-Asset                  | table     | postgres

See Common Smart Contract Design Patterns for a full description of Factory Smart Contract patterns.

Note

Cirrus API queries on contracts that are namespaced with a prefix must include the full (namespaced) contract name, such as "BlockApps-Asset" or "BlockApps-AssetFactory-Asset" to retrieve the correct contract.

Note

In STRATO v7.5, the table name separator was changed from a ":" (colon) to a "-" (dash).

Requiring Organization Membership

Smart Contract Application designers may now restrict functionality to users of a specific organization. This may be done with the tx.organization for SolidVM 3.0 and 3.2, or by querying the Certificate Registry Dapp in Cirrus to prefetch user identity in SolidVM ^3.3.

pragma solidvm 3.2;
contract ProjectManager {

  int projectCounter = 1;
  string ownerOrg;

  constructor() {
    ownerOrg = tx.organization;
  }

  function createProject() {
    require(tx.organization == ownerOrg, "You must be a member of ownerOrg to call this function");
    require(tx.organizationalUnit == "Product", "You must be in the Product Department to call this function");
    projectCounter++;
  }
}

Private Chain Membership

Private chains are a STRATO feature that allow for data to be shared privately with a desired set of members. These members can be individuals, departments, or entire organizations. Members of the private chains are represented as either an (orgName), or (orgName,orgUnit) or (orgName, orgUnit,commonName). These pairs of identifiers describe which groups of entities should be members of the chain. On a technical level, a member is a node in the STRATO network that has a X.509 identity allowing it to be associated with a specific org/orgUnit/commonName.

Governance contracts of a private chain can add organizations to the chain by emitting an event called OrganizationAdded and remove them using OrganizationRemoved. This allows any node with an X.509 certificate to connect to a private chain by being associated with an organization name and/or unit.

A group/organization can be a chain member by registering a certificate on-chain with the node's public key and associated group info that this node belongs to. Therefore Node Administrators must register the identity of their node's on-chain with a verified identity in order to allow a node to access private chains.

Whenever a new node with the same organizational information is added to the network or registered on-chain, the new node will automatically begin syncing with its peers. Similarly, if a node with an identity is taken down and restarted , it will automatically sync with its peers to fetch the necessary private chains upon boot up, as long as its public key is persisted (using ./strato --drop-chains).

OrganizationAdded event signature:

event OrganizationAdded(string orgName, string orgUnit, string commonName);
OrganizationRemoved event signature:

event OrganizationRemoved(string orgName, string orgUnit, string commonName);

Developers may specify any level of granularity of the entities within an organizations to add to a chain, by providing empty strings in the orgUnit and commonName fields. When these are omitted, all nodes matching the provided identity will be added/removed.

// define members by a specific org and unit within that org
event OrganizationAdded(string orgName, string orgUnit, "");
event OrganizationRemoved(string orgName, string orgUnit, "");

// define members by just their org
event OrganizationAdded(string orgName, "", "");
event OrganizationRemoved(string orgName, "", "");

The event takes four arguments:

  • string orgName
    • A member's organization (O) in their X.509 Certificate.
  • string orgUnit
    • The member's organizational unit (OU) in their X.509 Certificate.
  • string commonName
    • The member's Common Name (CN) in their X.509 Certificate.

The Organization/Unit/CommonName combination that is added or removed from a chain must strictly match the information contained within a node's certificate. event.

Example:

pragma solidvm 3.2;

contract dApp {

  int asset_data = 0; 

  event OrganizationAdded(string orgName, string orgUnit, string commonName);
  event OrganizationRemoved(string orgName, string orgUnit, string commonName);

  constructor(int x) {
    asset_data = x;
  }

  function getAsset() {
    return asset_data;
  }

  function addOrganization(string _org, string _unit, string _commonName, true) {
    emit OrganizationAdded(_org, _unit, _commonName);
  }

  function removeOrganization(string _org, string _unit, string _commonName, false) {
    emit OrganizationRemoved(_org, _unit, _commonName);
  }
}

Calling addOrganization will now associate any Verified Identity's organization (O), unit (OU) and commonName (CN) with the private chain ID that this smart contract was created on. addOrganization("blockapps", "engineering", "") will associate the private chain ID with all X.509 Certificates that are a part of blockapps/engineering and all private chain data shared with those peers. Conversely, removeOrganization("blockapps", "engineering", "") will disassociate the private chain ID with all X.509 Certificates that are a part of blockapps/engineering and corresponding private chain data will not be shared with those peers

SolidVM Certificate Utilities

SolidVM also offers built-in utility functions for certificates, which allow for easy parsing and verification.

Parsing Certificates

The parseCert function allows contracts to read the subject data of an X.509 certificate without registering it to the STRATO identity database. This function is available in SolidVM ^3.0.

The parseCert function has a similar signature as getUserCert:

function parseCert(string _cert) returns (mapping(string => string));

The function returns the subject information for this user's certificate as key/values:

  • commonName
    • The certificates' Common Name (CN)
  • organization
    • The certificates' Organization (O)
  • organizationalUnit
    • The certificates' Organizational Unit (OU)
  • country
    • The certificates' Country (C)
  • publicKey
    • The certificates' DER encoded Public Key
  • certString
    • The DER encoded string of this X.509 certificate
  • expirationDate
    • The Unix timestamp of the expiration of the certificate can be parsed as an int to be used in mathematical contexts.

Here is a simple example:

pragma solidvm 3.2;
contract identityParser {

  string myCommonName = "";
  string myCountry = "";
  string myOrganization = "";
  string myOrganizationalUnit = "";
  string myPublicKey = "";
  string myCertificate = "";
  int expirationDate = 0;
  constructor(string _cert) {
    mapping(string => string) certificate = parseCert(_cert);
    myCommonName   = parseCert(certificate)["commonName"];         // Get the common name
    myCountry      = parseCert(certificate)["country"];            // Get the country
    myOrganization = parseCert(certificate)["organization"];       // Get the organization
    myOrganizationalUnit = parseCert(certificate)["organizationalUnit"]; // Get the organizationalUnit
    myPublicKey    = parseCert(certificate)["publicKey"];          // Get the public-key
    myCertificate  = parseCert(certificate)["certString"];         // Get the cert string
    certExpirationDate = int(getUserCert(myAccount)["expirationDate"], 10); // Get the cert expirationDate
  }
}

Certificate Verification

VerifyCert

The verifyCert built-in function allows contracts to verify an X.509 certificate's signature with a given public key using ECDSA on the secp256k1 curve. This allows users to bypass the complex parsing and extraction of certificate data. This function is available in SolidVM ^3.2.

verifyCert signature:

function verifyCert(string _cert, string _pubkey) returns (bool);

Arguments:

  • string _cert
    • A DER encoded X.509 Certificate or X.509 Certificate Chain. Newlines replaced with '\n'.
  • string _pubkey
    • A DER encoded EC public key. Newlines replaced with '\n'.

The function returns true if the certificate is valid using the certificate validation rules mentioned above. The provided public key is used as the final Trust Anchor to verify the last certificate.

Example:

pragma solidvm 3.2;
contract CertVerifier {

  bool isValid;

  constructor(string _cert, string _pubkey) {
    isValid = verifyCert(_cert, _pubkey);
  }
}

VerifySignedBy

The verifySignedBy function allows users to easily check if a certificate was signed by a provided public key.

verifySignedBy signature:

function verifyCert(string _cert, string _pubkey) returns (bool);

Arguments:

  • string _cert
    • A DER encoded X.509 Certificate or X.509 Certificate Chain. Newlines replaced with '\n'.
  • string _pubkey
    • A DER encoded EC public key. Newlines replaced with '\n'.

The function returns true if the certificate is valid using the certificate validation rules mentioned above. The provided public key is used as the final Trust Anchor to verify the last certificate against.

Key/Certificate Command Reference

Note

This section is meant only for Node Administrators with access to a running STRATO instance.

The following are commands available in the strato_strato_1 container:

x509-generator

The x509-generator command creates new certificate files for use in STRATO. It takes the following arguments:

  • subject, s (required)
    • The name of the .json file containing the certificate subject information
    • Must exclusively have the following keys:
      • commonName : string
      • organization : string
      • organizationalUnit : string
      • country : string
      • pubKey : string
    • The public key must be hexadecimal encoded
  • key, k (required)
    • The name of the .pem file containing the EC private key used to sign this certificate
    • The private key must be DER encoded
  • issuer, i (optional)
    • The name of the .pem file of this certificate's issuer.
    • The certificate must be DER encoded
    • When omitted, the certificate being created will be self-issued.
    • When specified, the issuer certificate will be appended to the new certificate, creating a certificate chain.
  • output, o (optional)
    • The path of the output file to write the certificate to.
    • Defaults to "./outputCert.pem"
  • date, d (optional)
    • The expiration date of the certificate in the format YYYY-MM-DD.
    • Defaults to one year from the current date.

This command creates a .pem format, DER encoded X.509 certificate to the output file.

Successful execution results in the following output:

Done. Cert was written to outputCert.pem

x509-keygen

The x509-keygen is a simple utility that makes a new EC key for you compatible with STRATO and the x509-generator.

This command takes no arguments.

This command creates a .pem format, DER encoded EC private key in the priv.pem file in the current directory. It also creates a keydata.json file that contains the hex-encoded public and private key pairs, as well as the STRATO address that would be used for this key.

Successful execution results in the following output:

writing keydata to keydata.json
writing encoded private-key to priv.pem
{"privateKey":"346..9bcd","publicKey":"0423..50d","address":"769..2f"}

x509-info

The x509-info is a command that allows users to read a certificate .pem file in a human-readable format.

It takes the following argument:

  • cert, c:
    • The name of the .pem file containing the certificate to be read

Successful execution will output the following:

IIssuer {issCommonName = "Admin", issOrg = "BlockApps", issUnit = Just "Engineering", issCountry = Just "USA"}
Signature:
   R: "6f16d0f0d2e40c47b699627fa9ae2737cb7129cf06f51dbb658014bb3d79cc5d"
   S: "3c47450445065b177a8952de40d1915fd99981d25fd93e322f337f3780e177c7"
Signature (DER Encoding): "304402203c47450445065b177a8952de40d1915fd99981d25fd93e322f337f3780e177c702206f16d0f0d2e40c47b699627fa9ae2737cb7129cf06f51dbb658014bb3d79cc5d"
Certificate Hash: "68410110452c1179af159f85d3a4ae72aed12101fcb55372bc97c5108ef6e4d7"
Subject {subCommonName = "Admin", subOrg = "BlockApps", subUnit = Just "Engineering", subCountry = Just "USA", subPub = PublicKey "03521251e31fb06625fec592b69bfa70378d1cbc24b4500ed9d0307bb27cb96673"}
Subject Address: 74f014fef932d2728c6c7e2b4d3b88ac37a7e1d0
TRUE. This cert was signed by BlockApps

The last line is a useful indication of whether this certificate was directly signed by the BlockApps root key.

Note

This command-line tool was introduced in STRATO v7.6.