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]:
- The issuer of cert k is the subject of cert k + 1
- 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 has 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.
- The Unix timestamp of the expiration of the certificate and can be parsed as an
If an account does not have an identity on STRATO, the function will return a mapping with empty values for each key.
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.
STRATO Mercata uses 0x509
as the default address where the Certificate Registry dApp will exist on the network so that users and developers can easily reference its address and functions in the contractAdress
and method
fields of a transaction payload.
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.)
- The Subject Organizational Unit of this Certificate (prefer
- 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.
Transaction Built-in Properties
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
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
in SolidVM.
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 OrgAdded
and remove them using OrgRemoved
. 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
).
OrgAdded
event signature:
event OrgAdded(string orgName);
OrgRemoved
event signature:
event OrganizationRemoved(string orgName);
Developers may specify any level of granularity of the entities within an organizations to add to a chain, by using the addition OrgUnit
and CommonName
Added/Removed events. When these events are omitted, all nodes matching the provided identity will be added/removed.
// define members by a specific org and unit within that org
event OrgUnitAdded(string orgName, string orgUnit);
event OrgUnitRemoved(string orgName, string orgUnit);
// define members by their org, org unit, and the member's common name
event CommonNameAdded(string orgName, string orgUnit, sring commonName);
event CommonNameRemoved(string orgName, string orgUnit, sring commonName);
The events take up to three 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. Note this is the common name of a Node, not a user.
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 OrgUnitAdded(string orgName, string orgUnit);
event OrgUnitRemoved(string orgName, string orgUnit);
constructor(int x) {
asset_data = x;
}
function getAsset() {
return asset_data;
}
function addOrganization(string _org, string _unit) {
emit OrgUnitAdded(_org, _unite);
}
function removeOrganization(string _org, string _unit) {
emit OrgUnitRemoved(_org, _unit);
}
}
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("acme", "sales")
will associate the private chain ID with all X.509 Certificates that are a part of acme/sales
and all private chain data shared with those peers. Conversely, removeOrganization("acme", "sales")
will disassociate the private chain ID with all X.509 Certificates that are a part of acme/sales
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.
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.
- The Unix timestamp of the expiration of the certificate can be parsed as an
Here is a simple example:
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.
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:
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.
- The expiration date of the certificate in the format
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.