TIP  fast way to find definitions of a word

     Example 1   select NormalvsCompact
                 press [ctrl]+[f]
                 press [f3]

             2   select CompactTLS1.3
                 press [ctrl]+[f]
                 press [f3]

             3   select HMAC
                 press [ctrl]+[f]
                 press [f3]

TLS    Transport Layer Security
       uses TCP with port 443
TCP    Transmission Control Protocol
       defined in RFC793

T T'<x..y>  a vector of variable size
                        type T
                        
            = vecSize || vecValue

            vecSize   value = size in bytes of vecValue
                      size  = ceil(log2(y+1)/8) bytes

            ||        means concatenation

            vecValue  value = ByteArray of custom data
                      size  = vecSize value
            
            x = vecValue minimum size in bytes
            y = vecValue maximum size in bytes

            example  T           T'           <x..y>
                     CipherSuite cipher_suites<2..2^16-2>
   
CompactTLS1.3
    based on RFC8446

    SessionNew  map     Key  ^ ClientHello
                        Exch | + key_share*
                             | + signature_algorithms*
                             | + psk_key_exchange_modes*
                             v + pre_shared_key*       -------->
                                                                          ServerHello  ^ Key
                                                                         + key_share*  | Exch
                                                                    + pre_shared_key*  v
                                                                {EncryptedExtensions}  ^  Server
                                                                {CertificateRequest*}  v  Params
                                                                       {Certificate*}  ^
                                                                 {CertificateVerify*}  | Auth
                                                                           {Finished}  v
                                                       <--------   [ApplicationData*]
                             ^ {Certificate*}
                        Auth | {CertificateVerify*}
                             v {Finished}              -------->
                               [ApplicationData]       <------->    [ApplicationData]

                        symbols +   extensions sent in previously noted message
                                *   messages/extensions optional
                                                        situation dependent
                                                        not always sent
                                {}  messages protected by keys derived from [sender]_handshake_traffic_secret
                                []  messages protected by keys derived from [sender]_application_traffic_secret_N

    SessionRetry    uses HelloRetryRequest
                    map     ClientHello1
                            + key_share             -------->
                                                                      HelloRetryRequest
                                                    <--------               + key_share
                            ClientHello2
                            + key_share             -------->
                                                                            ServerHello
                                                                            + key_share
                                                                  {EncryptedExtensions}
                                                                  {CertificateRequest*}
                                                                         {Certificate*}
                                                                   {CertificateVerify*}
                                                                             {Finished}
                                                    <--------        [ApplicationData*]
                            {Certificate*}
                            {CertificateVerify*}
                            {Finished}              -------->
                            [ApplicationData]       <------->         [ApplicationData]

    SessionResume   Initial     map     ClientHello
                                        + key_share               -------->
                                                                                        ServerHello
                                                                                        + key_share
                                                                              {EncryptedExtensions}
                                                                              {CertificateRequest*}
                                                                                     {Certificate*}
                                                                               {CertificateVerify*}
                                                                                         {Finished}
                                                                  <--------      [ApplicationData*]
                                        {Certificate*}
                                        {CertificateVerify*}
                                        {Finished}                -------->
                                                                  <--------      [NewSessionTicket]
                                        [ApplicationData]         <------->       [ApplicationData]

                    noRRT   Initial NewSessionTicket had no early_data
                            has no Server Certificates because autentication depends on pre_shared_key
                            key_share may be sent to allow SessionResume change to SessionRetry
                            map     ClientHello
                                    + key_share*
                                    + pre_shared_key          -------->
                                                                                    ServerHello
                                                                               + pre_shared_key
                                                                                   + key_share*
                                                                          {EncryptedExtensions}
                                                                                     {Finished}
                                                              <--------      [ApplicationData*]
                                    {Finished}                -------->
                                    [ApplicationData]         <------->       [ApplicationData]

                    RRT     Initial NewSessionTicket had early_data
                            has no Server Certificates because autentication depends on pre_shared_key
                            key_share may be sent to allow SessionResume change to SessionRetry
                            Server does not wait to receive EndOfEarlyData to send ServerHello
                            map       ^ ClientHello
                                      | + early_data
                                0-RTT | + key_share*
                                      | + psk_key_exchange_modes
                                      | + pre_shared_key
                                      v (ApplicationData*)      -------->
                                                                                        ServerHello
                                                                                   + pre_shared_key
                                                                                       + key_share*
                                                                              {EncryptedExtensions}
                                                                                      + early_data*
                                                                                         {Finished}
                                                                <--------        [ApplicationData*]
                                      ^ (EndOfEarlyData)
                                1-RTT | {Finished}              -------->
                                      v [ApplicationData]       <------->         [ApplicationData]

                            0-RTT   zero round-trip time
                                    data is not forward secret
                                    attacker threats    duplicating network flight
                                                        using Client retry behavior then Server receives multiple copies of ApplicationData
                            1-RTT   one  round-trip time

    ClientHello sent  at start of Session
                      after receiving HelloRetryRequest

                struct {
                    ProtocolVersion legacy_version = 0x0303;
                    Random random;
                    opaque legacy_session_id<0..32>;
                    CipherSuite cipher_suites<2..2^16-2>;
                    opaque legacy_compression_methods<1..2^8-1>;
                    Extension extensions<8..2^16-1>;
                } ClientHello;

                ProtocolVersion uint16
                                0x0303 = TLS 1.2
                                0x0304 = TLS 1.3

                legacy_version  used for Middlebox compatability
                                not used by Server to select TLS version of Session

                random  size = 32 bytes
                        cryptographically secure
                        new generated by Client

                legacy_session_id  if Client wants no Middlebox compatability then size = 0 bytes
                                   if Client wants    Middlebox compatability then = unpredictable value
                                                                                   size = 32byte
                                   Server will use for ChangeCipherSpec

                cipher_suites  list of uint8 CipherSuite[2];
                               supported by Client
                               ordered preference descending

                legacy_compression_methods  = 0 = null
                                            size = 1byte
                                            if  wrong value or size
                                                then Server Alert illegal_parameter

                extensions  has supported_versions with ProtocolVersion = 0x0304
                                cookie if received HelloRetryRequest has cookie
                            may have    certificate_authorities
                                        signature_algorithms_cert
                                        post_handshake_auth
                                        server_name
                                        early_data  if sent before HelloRetryRequest
                            has no early_data       if sent after  HelloRetryRequest
                            pre_shared_key is last
                                else Server Alert illegal_parameter
                            if  has no pre_shared_key
                                then it has  signature_algorithms and
                                             supported_groups and
                                             key_share
                                else Server Abort missing_extension
                            if  has pre_shared_key and
                                sent after HelloRetryRequest
                                then update obfuscated_ticket_age
                                            binders
                            if  has no server_name
                                then Server may Alert missing_extension
                            if  started Sesion with TLS version < 1.3
                                then received supported_versions = 0x0304
                                then stay with TLS version < 1.3
                            Server ignores any unrecognized Extension

                if  sent with 0-RRT and
                    receive ServerHello with TLS version < 1.3
                    then Alert protocol_version

                put in Handshake then put in TLSPlaintext then send to peer

    ServerHello     sent  after ClientHello
                          if Server supports ClientHello parameters

                    struct {
                        ProtocolVersion legacy_version = 0x0303;
                        Random random;
                        opaque legacy_session_id_echo<0..32>;
                        CipherSuite cipher_suite;
                        uint8 legacy_compression_method = 0;
                        Extension extensions<6..2^16-1>;
                    } ServerHello;

                    legacy_version  used for Middlebox compatability
                                    not used by Client to select TLS version of Session

                    random  32 bytes
                            cryptographically secure
                            new generated by Server
                            last 8 bytes    = 44 4F 57 4E 47 52 44 01  if Server supports TLS version >= 1.2 and selects 1.2 for Session
                                            = 44 4F 57 4E 47 52 44 00  if Server supports TLS version >= 1.1 and selects 1.1 for Session
                            if  Client only supports TLS version 1.3
                                then last 8 bytes   != 44 4F 57 4E 47 52 44 01
                                                    != 44 4F 57 4E 47 52 44 00
                            if  received and does not follow these rules
                                then Client Alert illegal_parameter

                    legacy_session_id_echo  = ClientHello.legacy_session_id
                                            if  received and
                                                != ClientHello.legacy_session_id
                                                then Client Alert illegal_parameter

                    cipher_suite    one selected from ClientHello.cipher_suites
                                                      else Client Alert illegal_parameter

                    extensions  has supported_versions ProtocolVersion = 0x0304
                                        else Client Alert protocol_version
                                has no Extension different from ClientHello.extensions
                                has one or both pre_shared_key
                                                key_share
                                pre_shared_key may be last
                                if  started Sesion with TLS version < 1.3
                                    then received supported_versions = 0x0304
                                    then stay with TLS version < 1.3

                    put in Handshake then put in TLSPlaintext then send to peer

    HelloRetryRequest   sent  by Server
                              if received ClientHello has no sufficient information
                                  Example ClientHello key_share has DHE or ECDHE groups   unacceptable
                                                                                          unsupported
                        if  received more than one time in Session
                            then Alert unexpected_message
                        if  received with not enough data to generate different ClientHello
                            then Alert illegal_parameter

                        has HandshakeType = server_hello

                        struct {
                            ProtocolVersion legacy_version = 0x0303;
                            Random random;
                            opaque legacy_session_id_echo<0..32>;
                            CipherSuite cipher_suite;
                            uint8 legacy_compression_method = 0;
                            Extension extensions<6..2^16-1>;
                        } HelloRetryRequest;

                        random  = CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91 C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
                                = SHA256 of string "HelloRetryRequest"
                        legacy_session_id_echo  = ClientHello.legacy_session_id
                                                    else Client Alert illegal_parameter
                        cipher_suite    one selected from ClientHello.cipher_suites
                                                          else Client Alert illegal_parameter
                        extensions  has supported_versions ProtocolVersion = 0x0304
                                            else Client Alert illegal_parameter
                                    has no Extension different from extensions of ClientHello exept cookie
                                    may have  cookie
                                              key_share
                        put in Handshake then put in TLSPlaintext then send to peer

    EncryptedExtensions sent  by Server
                              after ServerHello
                              even if extensions = empty

                        struct { Extension extensions<0..2^16-1>; } EncryptedExtensions;

                        extensions  may have  supported_groups
                                              early_data
                                              server_name

                        put in Handshake then put in TLSPlaintext then convert to TLSCiphertext then send to peer

    CertificateRequest  sent  by Server
                              may be mutiple times
                              after  EncryptedExtensions in  SessionNew
                                                             SessionRetry
                                                             SessionResume Initial
                                     Server Finished at any time in  SessionResume noRRT
                                                                     SessionResume RRT

                        received then  accepts request by sending  Certificate       then
                                                                   CertificateVerify then
                                                                   Finished
                                       declines request by sending Certificate with empty certificate_list then
                                                                       Finished
                        if  received after Server Finished and
                            ClientHello had no post_handshake_auth
                            then Alert unexpected_message

                        struct {
                            opaque certificate_request_context<0..2^8-1>;
                            Extension extensions<2..2^16-1>;
                        } CertificateRequest;

                        certificate_request_context = random unpredictable bytes
                                                    size = zero if in    SessionNew
                                                                         SessionRetry
                                                                         SessionResume Initial
                                                         = nonzero if in SessionResume noRRT
                                                                         SessionResume RRT
                                                    prevents replay of Client CertificateVerify
                                                    unique for every Session

                        extension  must have signature_algorithms
                                   may  have signature_algorithms_cert
                                             certificate_authorities
                                             oid_filters
                                   Client ignores any unrecognized Extension

                        put in Handshake then put in TLSPlaintext then convert to TLSCiphertext then send to peer

    Certificate used to autenticate its sender

                struct {
                    opaque certificate_request_context<0..2^8-1>;
                    CertificateEntry certificate_list<0..2^24-1>;
                } Certificate;

                struct {
                    select (certificate_type) {
                        case RawPublicKey:  opaque ASN1_subjectPublicKeyInfo<1..2^24-1>; //RFC7250
                        case X509:          opaque cert_data<1..2^24-1>;
                    };
                    Extension extensions<0..2^16-1>;
                } CertificateEntry;

                enum {
                    X509(0),                //RFC5280
                    OpenPGP_RESERVED(1),
                    RawPublicKey(2),        //RFC7250
                    (255)
                } CertificateType;

                certificate_type    defined in received server_certificate_type
                                                        client_certificate_type
                                    = X509(0) = X.509v3     if received no  server_certificate_type
                                                                            client_certificate_type
                                    != OpenPGP_RESERVED(1)

                certificate_request_context = certificate_request_context from CertificateRequest if sent by Client
                                            = empty                                               if sent by Server

                certificate_list    certificates certify others in the list by signing them creating a signature chain
                                    signature chain may not follow certificate_list order
                                    may have extraneous certificates
                                    first certificate  belongs to sender
                                                       PrivateKey is possessed by sender
                                                       PublicKey is compatible with received signature_algorithms  if sent by Server
                                                       signature chain ends with TrustAnchor
                                    each certificate  signed using any algorithm from received signature_algorithms_cert
                                                                                               signature_algorithms if signature_algorithms_cert not received
                                                      has digitalSignature bit set    if has KeyUsage and sent by Server
                                    TrustAnchor  a certificate already trusted by receiver
                                                 may be self signed
                                                 signature is not validated by receiver
                                                 may not be in certificate_list if sender knowns receiver already has it
                                                 may be signed using algorithm not in received signature_algorithms
                                    at least one may be from certificate_authorities in CertificateRequest  if sent by Client
                                    includes only one CertificateEntry  if certificate_type = RawPublicKey
                                    nonempty    if sent by Client accepting CertificateRequest
                                    empty       if sent by Client declining CertificateRequest
                                    if  empty and received by Client then Client Alert decode_error
                                    if  empty and received by Server
                                        then Server continue Session without Client autentication
                                                    abort    Session Alert certificate_required
                                    if  invalid and received by Server
                                        then Server continue Session without Client autentication
                                                    abort    Session Alert specific to invalidity

                extensions  has extensions received in ClientHello        if sent by Server
                            has extensions received in CertificateRequest if sent by Client
                            a extension that applies to entire certificate_list may be in first CertificateEntry in certificate_list
                            KeyUsage            asserts all key usage bits  from oid_filters
                            ExtendedKeyUsage    has all key purpose OIDs    from oid_filters

                if  receviced with signature algorithm using    MD5 then    Alert bad_certificate
                                                                SHA1 then   must Alert bad_certificate  if not  TrustAnchor
                                                                            may  Alert bad_certificate  if      TrustAnchor
                keys are compatible with    signature_algorithms_cert   if received    signature_algorithms_cert
                                            signature_algorithms        if received no signature_algorithms_cert
                if  received by Server and
                    has not enough filters from oid_filters
                    then Server continue Session without Client authentication
                                abort    Session Alert unsupported_certificate

                put in Handshake then put in TLSPlaintext then convert to TLSCiphertext then send to peer

    CertificateVerify   sender proves possesion of PrivateKey of first certificate in certificate_list
                        provides Session integrity up to this point
                        sent after Certificate

                        struct {
                            SignatureScheme algorithm;
                            opaque signature<0..2^16-1>;
                        } CertificateVerify;

                        signature = SignatureAlgorithm(AA)
                            AA = BB || CC || 0x00 || Transcript-Hash(HandshakeContext, Certificate)
                            || means concatenaion
                            BB  each byte value = 32
                                size = 64 bytes
                            CC  = "TLS 1.3, server CertificateVerify"  if sent by Server
                                = "TLS 1.3, client CertificateVerify"  if sent by Client
                            SignatureAlgorithm  uses PrivateKey of first certificate in certificate_list
                                                compatible with    first certificate in certificate_list
                                                uses one from  signature_algorithms in ClientHello         if CertificateVerify sent by Server
                                                               signature_algorithms in CertificateRequest  if CertificateVerify sent by Client
                            if  first CertificateEntry in certificate_list uses RSA
                                then SignatureAlgorithm = RSASSA-PSS
                                                        != RSASSA-PKCS1-v1_5
                            SHA1 is not used

                        if receiver verification fails
                           then Alert decrypt_error

                        put in Handshake then put in TLSPlaintext then convert to TLSCiphertext then send to peer

    Finished    proves authentication of handshake and computed keys

                struct{ opaque verify_data[Hash.length]; } Finished;

                verify_data = HMAC(finished_key, Transcript-Hash(HandshakeContext, Certificate, CertificateVerify))
                            finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
                            BaseKey = [sender]_handshake_traffic_secret
                                    = [sender]_application_traffic_secret_N    if sent Post-Handshake
                            Certificate         only included if present
                            CertificateVerify   only included if present

                if  receiver verification fails
                    then Alert decrypt_error

                put in Handshake then put in TLSPlaintext then convert to TLSCiphertext then send to peer

    EndOfEarlyData  indicates  0-RTT ApplicationData messages have been transmitted
                    sent       by Client
                               after Server Finished
                               if received EncryptedExtensions with early_data

                    struct {} EndOfEarlyData;

                    encrypted using client_early_traffic_secret

    NewSessionTicket    sent    by Server
                                after Finished at any time
                                one or multiple times after each other or after specific events
                        used to create new  SessionResume noRRT
                                            SessionResume RRT

                        compatible with psk_key_exchange_modes

                        struct {
                            uint32 ticket_lifetime;
                            uint32 ticket_age_add;
                            opaque ticket_nonce<0..255>;
                            opaque ticket<1..2^16-1>;
                            Extension extensions<0..2^16-2>;
                        } NewSessionTicket;

                        ticket_lifetime time in seconds
                                        <= 604800
                                        BigEndian
                                        if = 0 then ticket should be discarded immediately
                                        validity may be shorter than the stated

                        ticket_age_add  securely generated
                                        unique value
                                        obscures the age of ticket

                        ticket_nonce    unique value for this connection

                        ticket  used as PSK identity
                                an opaque label
                                may be either   database lookup key
                                                self-encrypted and self-authenticated value

                        extensions  Clients ignores unrecognized extensions
                                    may have early_data
                                    if  has early_data
                                        then this NewSessionTicket can create new SessionResume RRT
                                    if  has no early_data
                                        then this NewSessionTicket can create new SessionResume noRRT

                        (new Session using NewSessionTicket) cipher suite KDF hash algorithm is equal to
                                              (this Session) cipher suite KDF hash algorithm

                        creates unique association between  this ticket value
                                                            secret PSK derived from resumption master secret

                        different servers using same Certificate may accept each other's NewSessionTicket

    KeyUpdate   sent  by  Client
                          Server
                      then all subsequent messages from Sender use next generation of keys

                if  received before sender Finished
                    then Alert unexpected_message

                struct { KeyUpdateRequest request_update; } KeyUpdate;
                enum { update_not_requested(0), update_requested(1), (255) } KeyUpdateRequest;

                request_update  = 0  if received then respond with KeyUpdate request_update = 1
                                = 1  if received then no response needed
                                > 1  if received then Alert illegal_parameter

                [sender]_application_traffic_secret_N+1 = HKDF-Expand-Label([sender]_application_traffic_secret_N,"traffic upd","",Hash.length)
                    first  compute [sender]_application_traffic_secret_N+1
                    second update  [sender]_Secret
                    third  compute [sender]_write_key
                                   [sender]_write_iv

    ApplicationData   is opaque to TLS
                      always encrypted
                      if theres nothing else to send then do close_notify

    ChangeCipherSpec  struct { enum { change_cipher_spec(1), (255) } type; } ChangeCipherSpec;

                      with  TLSPlaintext.length = 1
                            TLSPlaintext.fragment = 0x01

                      Client  if wants Middlebox compatability
                                 then if     in SessionResume RRT then sends after first ClientHello
                                      if not in SessionResume RRT then sends before either second ClientHello
                                                                                           Client encrypted handshake
                      Server  if wants Middlebox compatability or
                                 received ClientHello with legacy_session_id = nonempty
                                 then sends after either ServerHello
                                                         HelloRetryRequest

                      if received after first ClientHello in Session  and
                         received before peer Finished                and
                         has single byte value 0x01                   and
                         not encrypted in TLSCiphertext
                         then ignore it
                         else Alert unexpected_message

    Extension   struct {
                    ExtensionType extension_type;
                    opaque extension_data<0..2^16-1>;
                } Extension;
                enum {
                    server_name(0),                             //RFC6066
                    max_fragment_length(1),                     //RFC6066
                    status_request(5),                          //RFC6066
                    supported_groups(10),                       //RFC8422 RFC7919
                    signature_algorithms(13),                   //RFC8446
                    use_srtp(14),                               //RFC5764
                    heartbeat(15),                              //RFC6520
                    application_layer_protocol_negotiation(16), //RFC7301
                    signed_certificate_timestamp(18),           //RFC6962
                    client_certificate_type(19),                //RFC7250
                    server_certificate_type(20),                //RFC7250
                    padding(21),                                //RFC7685
                    pre_shared_key(41),                         //RFC8446
                    early_data(42),                             //RFC8446
                    supported_versions(43),                     //RFC8446
                    cookie(44),                                 //RFC8446
                    psk_key_exchange_modes(45),                 //RFC8446
                    certificate_authorities(47),                //RFC8446
                    oid_filters(48),                            //RFC8446
                    post_handshake_auth(49),                    //RFC8446
                    signature_algorithms_cert(50),              //RFC8446
                    key_share(51),                              //RFC8446
                    (65535)
                } ExtensionType;

                table   server_name                                     CH  EE
                        max_fragment_length                             CH  EE
                        status_request                              CH  CR  CT
                        supported_groups                                CH  EE
                        signature_algorithms                            CH  CR
                        use_srtp                                        CH  EE
                        heartbeat                                       CH  EE
                        application_layer_protocol_negotiation          CH  EE
                        signed_certificate_timestamp                CH  CR  CT
                        client_certificate_type                         CH  EE
                        server_certificate_type                         CH  EE
                        padding                                             CH
                        key_share                                   CH  SH HRR
                        pre_shared_key                                  CH  SH
                        psk_key_exchange_modes                              CH
                        early_data                                  CH  EE NST
                        cookie                                          CH HRR
                        supported_versions                          CH  SH HRR
                        certificate_authorities                         CH  CR
                        oid_filters                                         CR
                        post_handshake_auth                                 CH
                        signature_algorithms_cert                       CH  CR
                                                                    CH = ClientHello
                                                                    SH = ServerHello
                                                                    EE = EncryptedExtensions
                                                                    CT = Certificate
                                                                    CR = CertificateRequest
                                                                    NST = NewSessionTicket
                                                                    HRR = HelloRetryRequest
                        if  extension is in a message not listed
                            then receiver Alert illegal_parameter

            server_name Client must send to tell the Server name its contacting
                        received by Server then used     to send apropiate Server certificate
                                                         then send    server_name in EncryptedExtensions
                                                ignored  then send no server_name in EncryptedExtensions

                        helps Servers hosting multiple 'virtual' Servers at a single network address
                        must be supported

                        extension_data = ServerNameList if in ClientHello
                        extension_data = empty          if in EncryptedExtensions

                        struct { ServerName server_name_list<1..2^16-1> } ServerNameList;
                        struct {
                            NameType name_type;
                            select (name_type) {
                                case host_name: HostName;
                            } name;
                        } ServerName;
                        enum { host_name(0), (255) } NameType;
                        opaque HostName<1..2^16-1>;

                        server_name_list    has no repetitions of name_type
                                            if  ServerName is not recognized by Server
                                                then    abort    Session with Alert unrecognized_name
                                                        continue Session
                                            if  ServerName mismatch between Client and Server
                                                then client may decide to continue Session
                        host_name   refers to DNS hostnames
                        HostName    begins with a 16bit length
                                    represented as byte string
                                    case insensitive
                                    uses ASCII without trailing dot
                                    supports internationalized domain A-labels RFC5890
                                    has no literal IPv4 and IPv6 addresses
                                    algorithm to compare hostnames defined in RFC5890 Section 2.3.2.4

                        ServerName  may be  treated as opaque data
                                            passed to the application using TLS

                        if  Client wants to start SessionResume and
                            SNI provided externally is not valid for Server Certificate in SessionResume Initial
                            then Client must not start SessionResume
                        if  Client wants to start SessionResume and
                            SNI provided externally is not equal to SNI in SessionResume Initial
                            then Client may  not start SessionResume

                        SessionResume noRRT or RRT uses SNI in server_name ClientHello  of this Session
                                                                                        not of SessionResume Initial
                        SNI Server Name Identification
                            defined internally through server_name
                                    externally
                            no need for Server to associate SNI with each NewSessionTicket
                            may be stored with PSK by Clients

            supported_versions  indicates supported TLS versions by sender
                                used to select TLS version of Session
                                extension_data = SupportedVersions
                                    struct {
                                        select (Handshake.msg_type) {
                                            case client_hello: ProtocolVersion versions<2..254>;
                                            case server_hello: //and HelloRetryRequest
                                                               ProtocolVersion selected_version;
                                        };
                                    } SupportedVersions;
                                versions    ordered preference descending

            cookie  allows Server to reach Client at their apparent network
                    must be supported
                    use steps   1   Client sends ClientHello with no Cookie
                                2   Server decides to send HelloRetryRequest
                                3   Server makes hash of ClientHello
                                4   Server protects hash with any integrity algorithm
                                5   Server puts protected hash in Cookie in HelloRetryRequest
                                6   Client responds with ClientHello with copy of Cookie
                    extension_data = Cookie
                    struct { opaque cookie<1..2^16-1>; } Cookie;

            signature_algorithms    used for    CertificateVerify
                                                Certificate if received no signature_algorithms_cert

                                    extension_data = SignatureSchemeList
                                    struct { SignatureScheme supported_signature_algorithms<2..2^16-2>; } SignatureSchemeList;

                                    supported_signature_algorithms  ordered preference descending

                                    enum {
                                        //RSASSA-PKCS1-v1_5 algorithms RFC8017
                                        //used only in Certificate
                                            rsa_pkcs1_sha256(0x0401),       //must be supported for Certificate
                                            rsa_pkcs1_sha384(0x0501),
                                            rsa_pkcs1_sha512(0x0601),

                                        //ECDSA algorithms
                                        //curve defined in ANSI ANS X9.62-2005, FIPS 186-4
                                        //DER ecoded ECDSA-Sig-Value
                                            ecdsa_secp256r1_sha256(0x0403), //must be supported for CertificateVerify
                                            ecdsa_secp384r1_sha384(0x0503),
                                            ecdsa_secp521r1_sha512(0x0603),

                                        //RSASSA-PSS algorithms RFC8017
                                        //MGF1 mask generation function 1
                                        //Salt length = hash algorithm output length
                                        //PublicKey in X.509 uses rsaEncryption OID RFC5280
                                            rsa_pss_rsae_sha256(0x0804),    //must be supported for Certificate and CertificateVerify
                                            rsa_pss_rsae_sha384(0x0805),
                                            rsa_pss_rsae_sha512(0x0806),

                                        //EdDSA algorithms
                                        //PureEdDSA
                                        //no prehash
                                        //RFC8032
                                            ed25519(0x0807),
                                            ed448(0x0808),

                                        //RSASSA-PSS algorithms RFC8017
                                        //mask generation function 1
                                        //Salt length = hash algorithm output length
                                        //PublicKey in X.509 uses RSASSA-PSS OID RFC5756
                                        //Certificate signature parameters are DER encoded
                                        //PublicKey parameters = signature parameters
                                            rsa_pss_pss_sha256(0x0809),
                                            rsa_pss_pss_sha384(0x080a),
                                            rsa_pss_pss_sha512(0x080b),

                                        //Legacy algorithms
                                        //deprecated
                                        //not negotiated
                                            rsa_pkcs1_sha1(0x0201),
                                            ecdsa_sha1(0x0203),

                                        //Reserved Code Points
                                            private_use(0xFE00..0xFFFF),

                                        (0xFFFF)
                                    } SignatureScheme;

            signature_algorithms_cert   signature algorithms for Certificate
                                        must be supported
                                        extension_data = SignatureSchemeList

            certificate_authorities supported by sender
                                    used by receiver to fill certificate_list
                                    extension_data = CertificateAuthoritiesExtension
                                    struct {
                                        DistinguishedName authorities<3..2^16-1>;
                                    } CertificateAuthoritiesExtension;
                                    opaque DistinguishedName<1..2^16-1>;
                                    authorities uses    DER
                                                        ITU-T X.501
                                                can be  TrustAnchor subordinate CA

            oid_filters sent by Server for Client Certificate
                        extension_data = OIDFilterExtension
                        struct { OIDFilter filters<0..2^16-1>; } OIDFilterExtension;
                        struct {
                            opaque certificate_extension_oid<1..2^8-1>;
                            opaque certificate_extension_values<0..2^16-1>;
                        } OIDFilter;
                        filters has no OIDFilter repeated
                                OIDFilter   uses DER
                                            one _oid can have multiple _values
                                has no special anyExtendedKeyUsage OID

            post_handshake_auth sent by Client
                                indicates Clients could send Certificate after Finished
                                extension_data  = PostHandshakeAuth
                                                size = 0
                                struct {} PostHandshakeAuth;

            supported_groups    sent by Client then used by Server in this Session key exchange
                                sent by Server then used by Client in next Session to fill key_share
                                indicates all groups supported by sender
                                extension_data = NamedGroupList
                                struct { NamedGroup named_group_list<2..2^16-1>; } NamedGroupList;
                                named_group_list    ordered preference descending
                                enum {
                                    //Elliptic Curve Groups (ECDHE) FIPS 186-4 RFC7748 http://www.secg.org/sec2-v2.pdf
                                    secp256r1(0x0017),//must be supported
                                    secp384r1(0x0018),
                                    secp521r1(0x0019),
                                    x25519(0x001D), x448(0x001E),

                                    //Finite Field Groups (DHE) RFC7919
                                    ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102),
                                    ffdhe6144(0x0103), ffdhe8192(0x0104),

                                    //Reserved Code Points
                                    ffdhe_private_use(0x01FC..0x01FF),
                                    ecdhe_private_use(0xFE00..0xFEFF),
                                    (0xFFFF)
                                } NamedGroup;

            key_share   defines cryptographic paramenters for Session

                        extension_data = KeyShareClientHello        if in ClientHello
                        extension_data = KeyShareServerHello        if in ServerHello
                        extension_data = KeyShareHelloRetryRequest  if in HelloRetryRequest

                        struct { KeyShareEntry client_shares<0..2^16-1>; } KeyShareClientHello;
                        struct { KeyShareEntry             server_share; } KeyShareServerHello;
                        struct { NamedGroup              selected_group; } KeyShareHelloRetryRequest;

                        struct {
                            NamedGroup group;
                            opaque key_exchange<1..2^16-1>;
                        } KeyShareEntry;

                        client_shares   multiple KeyShareEntry  if sent before HelloRetryRequest
                                                                selected from           supported_groups ClientHello
                                                                with same order as      supported_groups ClientHello
                                                                may not have all from   supported_groups ClientHello
                                                                NamedGroup different                 from other NamedGroup   in client_shares
                                                                key_exchange generated independently from other key_exchange in client_shares
                                        one      KeyShareEntry  if sent after HelloRetryRequest
                                                                selected from selected_group HelloRetryRequest
                                        empty                   if Client wants HelloRetryRequest
                                        if  received and breaks any rule
                                            then Server Alert illegal_parameter

                        selected_group  one NamedGroup selected from supported_groups of ClientHello
                                        not sent if using psk_ke PskKeyExchangeMode
                                        if  received and breaks any rule
                                            then Client Alert illegal_parameter

                        server_share    has NamedGroup  = one in client_shares ClientHello      if sent before HelloRetryRequest
                                                        = selected_group HelloRetryRequest      if sent after  HelloRetryRequest
                                        not sent if using psk_ke PskKeyExchangeMode
                                        if  received and breaks any rules
                                            then Client Alert illegal_parameter

                        key_exchange    = PublicValue
                                        DH  Finite Field Diffie-Hellman
                                            defined in RFC7919 Appendix A
                                            PublicValue = Y for the specified group RFC7919
                                                        = g^X mod p
                                                        1 < Y < p-1
                                                        BigEndian
                                                        left padded with zeros
                                                        size with pad = p bytes
                                                        these rules are verified by receiver
                                            in one DH group the padding results in all public keys having same length
                                        ECDHE   Elliptic Curve Diffie-Hellman
                                                if  secp256r1 or secp384r1 or secp521r1
                                                    then PublicValue = UncompressedPointRepresentation
                                                                     struct {
                                                                         uint8 legacy_form = 4;
                                                                         opaque X[coordinate_length];
                                                                         opaque Y[coordinate_length];
                                                                     } UncompressedPointRepresentation;
                                                                     X Y each    BigEndian
                                                                                 left padded with zeros
                                                                                 size with pad = 32 if secp256r1
                                                                                                 48 if secp384r1
                                                                                                 66 if secp521r1
                                                                                 have correct    interval
                                                                                                 solution of eliptic curve equation
                                                                         point not at infinity
                                                                         these rules are verified by receiver
                                                                     no need to verify membership in correct subgroup
                                                if  X25519 or X448
                                                    then PublicValue    = byte strings inputs and outputs of functions from RFC7748
                                                                        size =  32 if X25519
                                                                                56 if X448

            psk_key_exchange_modes  supported by Client
                                    sent    by Client
                                            with pre_shared_key else Server abort Session
                                    used in current Session PSKs
                                            NewSessionTicket

                                    extension_data = PskKeyExchangeModes
                                    struct { PskKeyExchangeMode ke_modes<1..255>; } PskKeyExchangeModes;
                                    enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;

                                    psk_ke  PSK only key establishment mode
                                            Server then sends no key_share
                                    psk_dhe_ke  PSK with (EC)DHE key establishment mode
                                                Client and Server then send key_share

            early_data  extension_data = EarlyDataIndication
                        struct {
                            select (Handshake.msg_type) {
                                case new_session_ticket:   uint32 max_early_data_size;
                                case client_hello:         Empty;
                                case encrypted_extensions: Empty;
                            };
                        } EarlyDataIndication;
                        struct {} Empty;

                        max_early_data_size = 0-RTT ApplicationData size max limit
                                            counts TLSInnerPlaintext.content
                                            does not count  TLSInnerPlaintext.type
                                                            TLSInnerPlaintext.zeros

                        if  received 0-RTT ApplicationData size > max_early_data_size
                            then Server may Alert unexpected_message

                        if  received NewSessionTicket with early_data
                            then Client can use it for new SessionResume RRT

                        if  received ClientHello with early_data
                            then Server do  SessionRetry    sending HelloRetryRequest and
                                                                ignoring 0-RRT  using max_early_data_size
                                            SessionResume RRT   ignoring 0-RRT  using max_early_data_size
                                                                                until bein able to decrypt 1-RRT data
                                                                    EncryptedExtensions will have no early_data
                                                                decrypting 0-RRT
                                                                    EncryptedExtensions will have early_data
                                                                    if  0-RRT decryption fails
                                                                        then Alert bad_record_mac

            pre_shared_key  extension_data = PreSharedKeyExtension
                            struct {
                                select (Handshake.msg_type) {
                                    case client_hello: OfferedPsks;
                                    case server_hello: uint16 selected_identity;
                                };
                            } PreSharedKeyExtension;

                            struct {
                                PskIdentity identities<7..2^16-1>;
                                PskBinderEntry binders<33..2^16-1>;
                            } OfferedPsks;

                            struct {
                                opaque identity<1..2^16-1>;
                                uint32 obfuscated_ticket_age;
                            } PskIdentity;

                            opaque PskBinderEntry<32..255>;

                            selected_identity   0-base index value
                                                selected    by Server
                                                            from OfferedPsks
                                                            then    validates binder
                                                                    if  validation fails
                                                                        then abort Session and do not select another OfferedPsks
                                                received by Client then validates   0-base index value range
                                                                                    binders hash matches CipherSuite ServerHello
                                                                                    key_share is present if required by psk_key_exchange_modes
                                                                                    if  validation fails
                                                                                        then Abort illegal_parameter
                                                = 0 indicates   Server is not ignoring 0-RRT data
                                                                EncryptedExtensions will have early_data
                                                    then Server validates binder associated TLS version
                                                                                            CipherSuite
                                                                                            ALPN RFC7301 if any
                                                                if  validation fails
                                                                    then send no pre_shared_key and
                                                                        do  SessionRetry    sending HelloRetryRequest and
                                                                                                ignoring 0-RRT  using max_early_data_size
                                                                            SessionResume RRT   ignoring 0-RRT  using max_early_data_size
                                                                                                                until bein able to decrypt 1-RRT data
                                                                                                    EncryptedExtensions will have no early_data
                                                if  != 0 and receives EncryptedExtensions with early_data
                                                    then Client Alert illegal_parameter
                            identities  list supported by Client

                            binders list of HTHT values
                                    one for each value in identities
                                    same order as identities
                                    each uses hash algorithm defined    by CipherSuite from previous Session with NewSessionTicket
                                                                        externally with PSK established externally
                                                                        if not defined then use SHA-256
                                    HTHT    = HMAC(finished_key, Transcript-Hash(Truncate(ClientHello)))                                    if not in SessionRetry
                                            = HMAC(finished_key, Transcript-Hash(ClientHello1, HelloRetryRequest, Truncate(ClientHello2)))  if in SessionRetry
                                                finished_key = HKDF-Expand-Label(binder_key, "finished", "", Hash.length)
                                                TruOut  = Truncate()
                                                        only removes ClientHello.extensions.OfferedPsks.binders
                                                        all length fields of ClientHello are set as if binders was not removed
                                                            including   overall length
                                                                        extensions length
                                                                        pre_shared_key length

                            identity    label for PSK established   internally using NewSessionTicket
                                                                    externally

                            obfuscated_ticket_age   = (TAGE + TAGEA) % 2^32
                                                        TAGE    time since the receipt of NewSessionTicket
                                                                in milliseconds
                                                                < ticket_lifetime converted to milliseconds
                                                        TAGEA   ticket_age_add converted to milliseconds
                                                    prevents passive observers from correlating connections unless tickets are reused
                                                    may be = 0 if established externally
                                                    if = 0 then its ignored by Server
                                                    Server validates    TAGE = (obfuscated_ticket_age % 2^32) - TAGEA
    Handshake   struct{ HandshakeType msg_type;
                        uint24 length;
                        select (Handshake.msg_type) {
                            case client_hello:          ClientHello;
                            case server_hello:          ServerHello;
                            case end_of_early_data:     EndOfEarlyData;
                            case encrypted_extensions:  EncryptedExtensions;
                            case certificate_request:   CertificateRequest;
                            case certificate:           Certificate;
                            case certificate_verify:    CertificateVerify;
                            case finished:              Finished;
                            case new_session_ticket:    NewSessionTicket;
                            case key_update:            KeyUpdate;
                        };
                    } Handshake;
                length  = sizeof(Handshake)-4 bytes

                enum {  hello_request_RESERVED(0),
                        client_hello(1),
                        server_hello(2),
                        hello_verify_request_RESERVED(3),
                        new_session_ticket(4),
                        end_of_early_data(5),
                        hello_retry_request_RESERVED(6),
                        encrypted_extensions(8),
                        certificate(11),
                        server_key_exchange_RESERVED(12),
                        certificate_request(13),
                        server_hello_done_RESERVED(14),
                        certificate_verify(15),
                        client_key_exchange_RESERVED(16),
                        finished(20),
                        certificate_url_RESERVED(21),
                        certificate_status_RESERVED(22),
                        supplemental_data_RESERVED(23),
                        key_update(24),
                        message_hash(254),
                        (255)
                    } HandshakeType;
                    _RESERVED    not used in TLS version 1.3

                if  received unknown HandshakeType
                    then Alert unexpected_message

    RecordLayer all sent or received messages are processed through TLSRecords

                TLSRecords  TLSPlaintext
                            TLSCiphertext

                TLSPlaintext   struct {
                                   ContentType type;
                                   ProtocolVersion legacy_record_version;
                                   uint16 length;
                                   opaque fragment[TLSPlaintext.length];
                               } TLSPlaintext;

                               enum {
                                   invalid(0),
                                   change_cipher_spec(20),
                                   alert(21),
                                   handshake(22),
                                   application_data(23),
                                   (255)
                               } ContentType;

                               legacy_record_version  deprecated
                                                      must be = 0x0303  if fragment contains no first ClientHello in Session
                                                      may  be = 0x0301  if fragment contains    first ClientHello in Session and
                                                                           Client wants compatability with previous TLS versions
                               length  in bytes
                                       <= 2^14 bytes else Alert record_overflow

                               fragment  block of data being transmitted
                                         may contain more than one Handshake  if type = handshake(22) and
                                                                                 no other type in between
                                                     less than one Handshake  if type = handshake(22)
                                         if key change occurs not at fragment boundary
                                            then receiver Alert unexpected_message
                                         has only one Alert  if type = alert(21)
                                         may be empty        if type = application_data(23)
                                         is not empty        if type = handshake(22)

                TLSCiphertext  uses AEAD  Authenticated Encryption with Associated Data
                                          algorithm expansion < 256 bytes  for TLS 1.3
                                          RFC5116
                               struct {
                                   ContentType opaque_type = application_data(23);
                                   ProtocolVersion legacy_record_version = 0x0303;
                                   uint16 length;
                                   opaque encrypted_record[TLSCiphertext.length];
                               } TLSCiphertext;

                               opaque_type            for Middlebox compatibility
                                                      actual content type in TLSInnerPlaintext.type

                               legacy_record_version  = 0x0303 = TLS v1.2

                               length                 = size of TLSInnerPlaintext + AEAD algorithm expansion
                                                      <= 2^14 + 256 bytes  else Alert record_overflow

                               encrypted_record = AEADEncrypted = AEAD-Encrypt(write_key, preRecordNonceW, additional_data, plaintext)
                                                                write_key       = [sender]_write_key
                                                                preRecordNonceW = padedNonceW XOR [sender]_write_iv
                                                                                padedNonceW = zerosPad || write_nonce
                                                                                            size = iv_length
                                                                write_nonce 64bit integer
                                                                            BigEndian
                                                                            = write_nonce+1  each time after running AEAD-Encrypt
                                                                            = 0              if start of Session or
                                                                                                changing [sender]_write_key
                                                                            never wraps
                                                                            if about to wrap then  close Session or
                                                                                                   do KeyUpdate
                                                                additional_data = TLSCiphertext.opaque_type ||
                                                                                  TLSCiphertext.legacy_record_version ||
                                                                                  TLSCiphertext.length

                                                                plaintext = TLSInnerPlaintext

                                                                struct {
                                                                    opaque content[TLSPlaintext.length];
                                                                    ContentType type;
                                                                    uint8 zeros[length_of_padding];
                                                                } TLSInnerPlaintext;

                                                                TLSInnerPlaintext  content = TLSPlaintext.fragment
                                                                                           length <= 2^14
                                                                                   type    = TLSPlaintext.type
                                                                                   zeros   = 0
                                                                                           length is customizable
                                                                                           used to hide length of content
                                                                                   if type = application_data
                                                                                      then content length may = 0
                                                                                   if type = Handshake or Alert
                                                                                      and  content length = 0
                                                                                      then Alert unexpected_message

                                                  AEADDecrypted = AEAD-Decrypt(write_key, preRecordNonceR, additional_data, AEADEncrypted)
                                                                = plaintext
                                                                write_key       = [sender]_write_key
                                                                preRecordNonceR = padedNonceR XOR [sender]_write_iv
                                                                                padedNonceR = zerosPad || read_nonce
                                                                                            size = iv_length
                                                                read_nonce  64bit integer
                                                                            BigEndian
                                                                            = read_nonce+1  each time after running AEAD-Decrypt
                                                                            = 0             if starting of Session
                                                                                               changing [sender]_write_key
                                                                            never wraps
                                                                            if its going to wrap then   close Session
                                                                                                        do KeyUpdate
                                                                additional_data = TLSCiphertext.opaque_type ||
                                                                                  TLSCiphertext.legacy_record_version ||
                                                                                  TLSCiphertext.length

                                                                plaintext  = TLSInnerPlaintext
                                                                           read backwards counting each byte until nonZeroByte
                                                                                     this count = length_of_padding
                                                                                     this nonZeroByte = TLSInnerPlaintext.type

                                                                if fails then Alert bad_record_mac

    CipherSuite from  TLS  = 1.3 cannot be used for TLS <= 1.2
                      TLS <= 1.2 cannot be used for TLS  = 1.3

                all ciphers modeled as AEAD

                uint8 CipherSuite[2];

                TLS_AES_128_GCM_SHA256       = {0x13,0x01};  //RFC5116
                TLS_AES_256_GCM_SHA384       = {0x13,0x02};  //RFC5116
                TLS_CHACHA20_POLY1305_SHA256 = {0x13,0x03};  //RFC8439
                TLS_AES_128_CCM_SHA256       = {0x13,0x04};  //RFC5116
                TLS_AES_128_CCM_8_SHA256     = {0x13,0x05};  //RFC6655

                TLS_AES_128_GCM_SHA256  must be supported
                                        AEAD_AES_128_GCM  AEAD-Encrypt = GCM-AE K (IV, P, A)
                                                          AEAD-Decrypt = GCM-AD K (IV, C, A, T)
                                                          K   = write_key
                                                              size = 16 bytes = key_length
                                                          IV  = preRecordNonceW if Encrypt
                                                              = preRecordNonceR if Decrypt
                                                              size = 12 bytes = iv_length
                                                          P   = plaintext
                                                              size <= 2^36 - 31
                                                          A   = additional_data
                                                          C   = encrypted_record wihtouth last 16 bytes
                                                          T   = last 16 bytes in encrypted_record
                                                          https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
                                                          CIPH  = Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
                                                                used in GCM-AE
                                                                        GCM-AD
                                                                https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
                                        SHA256  = Hash
                                                output size = 32 bytes

    [sender]_write_key = HKDF-Expand-Label([sender]_Secret, "key", "", key_length)
    [sender]_write_iv  = HKDF-Expand-Label([sender]_Secret,  "iv", "",  iv_length)

    if ContentType = Handshake                 then [sender]_Secret = [sender]_handshake_traffic_secret
       ContentType = ApplicationData           then [sender]_Secret = [sender]_application_traffic_secret_N
       ContentType = ApplicationData and 0-RTT then [sender]_Secret = client_early_traffic_secret

    HandshakeContext = ClientHello || ... || later of EncryptedExtensions/CertificateRequest if sent by Server
                     = ClientHello || ... || later of Server Finished/EndOfEarlyData         if sent by Client
                     = ClientHello || ... || Client Finished + CertificateRequest            if sent Post-Handshake

    EarlySecret = HKDF-Extract(HLZ, PSK)
                    PSK = pre-shared key established externally                                                 if PSK is     used in Session
                        = HKDF-Expand-Label(resumption_master_secret, "resumption", ticket_nonce, Hash.length)  if PSK is     used in Session
                        = HLZ                                                                                   if PSK is not used in Session
    binder_key                      = Derive-Secret(EarlySecret, BinderStrg, "")
    client_early_traffic_secret     = Derive-Secret(EarlySecret, "c e traffic", ClientHello)
    early_exporter_master_secret    = Derive-Secret(EarlySecret, "e exp master", ClientHello)

    BinderStrg  = "ext binder" if PSK was provisioned outside of TLS
                = "res binder" if PSK was provisioned as resumption master secret of previous handshake

    HandshakeSecret                 = HKDF-Extract(Derive-Secret(EarlySecret, "derived", ""), (EC)DHESharedSecret)
    client_handshake_traffic_secret = Derive-Secret(HandshakeSecret, "c hs traffic", ClientHello...ServerHello)
    server_handshake_traffic_secret = Derive-Secret(HandshakeSecret, "s hs traffic", ClientHello...ServerHello)

    MasterSecret                        = HKDF-Extract(Derive-Secret(HandshakeSecret, "derived", ""), HLZ)
    client_application_traffic_secret_0 = Derive-Secret(MasterSecret, "c ap traffic", ClientHello...Server Finished)
    server_application_traffic_secret_0 = Derive-Secret(MasterSecret, "s ap traffic", ClientHello...Server Finished)
    exporter_master_secret              = Derive-Secret(MasterSecret,   "exp master", ClientHello...Server Finished)
    resumption_master_secret            = Derive-Secret(MasterSecret,   "res master", ClientHello...Client Finished)

    if  a secret is not available
        then secret = HLZ

    HLZ = 0
        size = Hash.length

    Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length)
    HKDF-Expand-Label(Secret, Label, Context, Length) = HKDF-Expand(Secret, HkdfLabel, Length)
                                                        put Context inside HkdfLabel
                                                        struct {
                                                            uint16 length = Length;
                                                            opaque label<7..255> = "tls13 " + Label;
                                                            opaque context<0..255> = Context;
                                                        } HkdfLabel;
    (EC)DHESharedSecret = SharedSecret
                        Finite Field Diffie-Hellman
                            SharedSecret = negotiated key(Z)
                                           converted to byte array
                                           BigEndian
                                           LeftPadded with zeros
                                           size of the prime
                        Elliptic Curve Diffie-Hellman
                            RFC7748
                            if secp256r1 or secp384r1 or secp521r1
                               then SharedSecret = FE2OSP(Z)
                                                     Field Element to Octet String Conversion Primitive
                                                     Z = x-coordinate of ECDH shared secret curve point
                                                     defined in IEEE Std. 1363-2000
                                                 = x-coordinate in big endian
                                                 size = 32 bytes  if secp256r1
                                                 size = 48 bytes  if secp384r1
                                                 size = 66 bytes  if secp521r1
                            if X25519 or X448
                               then KeyShareEntry.key_exchange public key = ScalMul(SecKe, StPuBsp)
                                                                            SecKe   secret key
                                                                                    has appropriate length
                                                                            StPuBsp standard public basepoint
                                    SharedSecret = ScalMul(SecKe, PePuKe)
                                                    SecKe  = secret key
                                                    PePuKe = peer's public key
                                    ScalMul = ScalMul( scalar, u-coordinate point )
                                            ECDH scalar multiplication function

    HMAC  keyed-hash message authentication code
          used to verify data integrity of a message
          not vulnerable to LengthExtensionAttack
          key   is a secret cryptographic key
          hash  is an algorithm like  MD5
                                      SHA256
          RFC2104
          = HMAC(key, message)
          = hash( (k xor opad)  || hash( (k xor ipad) || message ) )
              k   = key                   if keySize = hashBlockSize
                  = key       || zpad     if keySize < hashBlockSize
                  = hash(key) || zpad     if keySize > hashBlockSize
              zpad    = all bytes set to 0x00
                      size = hashBlockSize - keySize          if keySize < hashBlockSize
                           = hashBlockSize - hashOutputSize   if keySize > hashBlockSize
              opad    = all bytes set to 0x5c
                      size = hashBlockSize
              ipad    = all bytes set to 0x36
                      size = hashBlockSize
          if  hash = SHA256
              then  hashBlockSize  = 512bits = 64bytes
                    hashOutputSize = 256bits = 32bytes
                                            
    HKDF    HMAC-based Extract-and-Expand Key Derivation Function
            RFC5869
            PRK pseudo random key
                = HKDF-Extract(salt, IKM)
                = HMAC-Hash(salt, IKM)
                salt  optional
                      random
                      non secret
                      used by HMAC as the key
                IKM   input keying material
                      used by HMAC as the message
                Hash  defined by CipherSuite
                      output length = HashLen
                if  salt not provided
                    then salt   = all bytes set to zero
                                size = HashLen

            OKM output keying material
                = HKDF-Expand(PRK, info, L)
                = first L octets of T
                = generate T until its size >= L
                  T = T(1) || T(2) || T(3) || ... || T(N)
                      N = ceil(L/HashLen)
                      T(0) = empty string zero length
                      T(1) = HMAC-Hash(PRK, T(0) || info || 0x01)
                      T(2) = HMAC-Hash(PRK, T(1) || info || 0x02)
                      T(3) = HMAC-Hash(PRK, T(2) || info || 0x03) ...
                      || means concatenation
                      counter 0x01 0x02 0x03 ... size = 8bits
                PRK size >= HashLen
                info    optional context
                        application specific information
                        may be zerolength string
                L   length of OKM in bytes
                    <= 255*HashLen

    TanscriptHash  Transcript-Hash(M1, M2, ... Mn) = Hash(M1 || M2 || ... || Mn)
                       each M# = TLSPlaintext.fragment
                       may have  ClientHello || HelloRetryRequest || ClientHello || ServerHello ||
                                 EncryptedExtensions || Server CertificateRequest || Server Certificate ||
                                 Server CertificateVerify || Server Finished || EndOfEarlyData ||
                                 Client Certificate || Client CertificateVerify || Client Finished
                   if  Session has HelloRetryRequest
                       then Transcript-Hash(cli1hush, HelloRetryRequest, ... Mn) = Hash( cli1hush || HelloRetryRequest  || ... || Mn)
                            cli1hush = Handshake.msg_type = message_hash = 254
                                                .length   = HashLen
                                                .content  = Hash(TLSPlaintext.fragment of ClientHello1)

    TLS-Exporter(label, context_value, key_length) = HKDF-Expand-Label( Derive-Secret(SecretExp, label, ""),
                                                                        "exporter",
                                                                        Hash(context_value),
                                                                        key_length  )
                                                    SecretExp  = exporter_master_secret
                                                               = early_exporter_master_secret
                                                                   used in 0-RTT
                                                    if  no context provided
                                                        then context_value = zero length

    StateMachine    [] indicates actions for specific circumstances
                    "K_{send,recv} = foo" means set send/recv key to the given key

                    Client
                                                  START <----+
                                   Send ClientHello |        | Recv HelloRetryRequest
                              [K_send = early data] |        |
                                                    v        |
                               /                 WAIT_SH ----+
                               |                    | Recv ServerHello
                               |                    | K_recv = handshake
                           Can |                    V
                          send |                 WAIT_EE
                         early |                    | Recv EncryptedExtensions
                          data |           +--------+--------+
                               |     Using |                 | Using certificate
                               |       PSK |                 v
                               |           |            WAIT_CERT_CR
                               |           |        Recv |       | Recv CertificateRequest
                               |           | Certificate |       v
                               |           |             |    WAIT_CERT
                               |           |             |       | Recv Certificate
                               |           |             v       v
                               |           |              WAIT_CV
                               |           |                 | Recv CertificateVerify
                               |           +> WAIT_FINISHED <+
                               |                  | Recv Finished
                               \                  | [Send EndOfEarlyData]
                                                  | K_send = handshake
                                                  | [Send Certificate [+ CertificateVerify]]
                        Can send                  | Send Finished
                        app data   -->            | K_send = K_recv = application
                        after here                v
                                              CONNECTED

                        clients may send Alerts from post-ServerHello messages  in the clear or
                                                                                with the early data keys
                            if  sending these Alerts
                                then clients should first rekey to the handshake keys

                    Server
                                                      START <-----+
                                       Recv ClientHello |         | Send HelloRetryRequest
                                                        v         |
                                                     RECVD_CH ----+
                                                        | Select parameters
                                                        v
                                                     NEGOTIATED
                                                        | Send ServerHello
                                                        | K_send = handshake
                                                        | Send EncryptedExtensions
                                                        | [Send CertificateRequest]
                         Can send                       | [Send Certificate + CertificateVerify]
                         app data                       | Send Finished
                         after   -->                    | K_send = application
                         here                  +--------+--------+
                                      No 0-RTT |                 | 0-RTT
                                               |                 |
                           K_recv = handshake  |                 | K_recv = early data
                         [Skip decrypt errors] |    +------> WAIT_EOED -+
                                               |    |       Recv |      | Recv EndOfEarlyData
                                               |    | early data |      | K_recv = handshake
                                               |    +------------+      |
                                               |                        |
                                               +> WAIT_FLIGHT2 <--------+
                                                        |
                                               +--------+--------+
                                       No auth |                 | Client auth
                                               |                 |
                                               |                 v
                                               |             WAIT_CERT
                                               |        Recv |       | Recv Certificate
                                               |       empty |       v
                                               | Certificate |    WAIT_CV
                                               |             |       | Recv
                                               |             v       | CertificateVerify
                                               +-> WAIT_FINISHED <---+
                                                        | Recv Finished
                                                        | K_recv = application
                                                        v
                                                    CONNECTED
    Alert   struct {
                AlertLevel level;
                AlertDescription description;
            } Alert;

            enum { warning(1), fatal(2), (255) } AlertLevel;
            enum {
                close_notify(0),
                unexpected_message(10),
                bad_record_mac(20),
                record_overflow(22),
                handshake_failure(40),
                bad_certificate(42),
                unsupported_certificate(43),
                certificate_revoked(44),
                certificate_expired(45),
                certificate_unknown(46),
                illegal_parameter(47),
                unknown_ca(48),
                access_denied(49),
                decode_error(50),
                decrypt_error(51),
                protocol_version(70),
                insufficient_security(71),
                internal_error(80),
                inappropriate_fallback(86),
                user_canceled(90),
                missing_extension(109),
                unsupported_extension(110),
                unrecognized_name(112),
                bad_certificate_status_response(113),
                unknown_psk_identity(115),
                certificate_required(116),
                no_application_protocol(120),
                (255)
            } AlertDescription;

            level   ignored by receiver
                    replaced by Class in TLS v1.3

            Class   defined in each AlertDescription
                    Closure  notifies connection is ending
                             used to avoid truncation attack
                             level = warning(1)
                    Error    level = fatal(2)
                             if  sent or received
                                 then immediately close connection
                    Unknown  = Error

            close_notify    send if sender will not send any more messages on this Session
                                    user cancels operation after Handshake complete
                            if received then subsecuent received messages are     ignored
                            if sent     then subsecuent received messages are not ignored
                            Class Closure

            user_canceled   send if canceling Handshake not because of protocol failure
                            may be followed by close_notify
                            Class Closure

            unexpected_message  send if inappropriate message was received
                                Example  wrong order of handshake messages
                                         received prematurely ApplicationData
                                Class Error

            bad_record_mac  send if received record cannot be deprotected
                            Class Error

            record_overflow send if received    TLSCiphertext size > 2^14 + 256 bytes
                                                TLSPlaintext  size > 2^14 bytes
                            Class Error

            handshake_failure   send if unacceptable security parameters from available options
                                Class Error

            bad_certificate send if received corrupt certificate
                                    Example certificate signatures did not verify correctly
                            Class Error

            unsupported_certificate send if received certificate has unsupported type
                                    Class Error

            certificate_revoked send if received certificate was revoked by its signer.
                                Class Error

            certificate_expired send if received certificate expired or is invalid
                                Class Error

            certificate_unknown send if received certificate has unspecified issue
                                Class Error

            illegal_parameter   send if received    Handshake with incorrect or inconsistent fields
                                                    message is syntactically correct but semantically invalid
                                Class Error

            unknown_ca  send if received valid certificate chain or partial chain and
                                         CA certificate could not be located or matched with known TrustAnchor
                        Class Error

            access_denied   send if received valid certificate or PSK and
                                    access control applied and
                                    decide not to proceed with negotiation
                            Class Error

            decode_error    send if received message has    incorrect protocol syntax
                                                            some field out of range
                                                            incorrect length
                            Class Error

            decrypt_error   send if handshake cryptographic operation failed
                                    Example unable to   verify Signature
                                                        validate    Finished
                                                                    PskBinder
                                            invalid PSK identity
                            Class Error

            protocol_version    send if received TLS version is recognized and
                                                                not supported
                                Class Error

            insufficient_security   send if negotiated handshake parameters are acceptable and
                                                                            more secure needed
                                    Class Error

            internal_error  send if internal error unrelated to peer or protocol correctness
                            Class Error

            inappropriate_fallback  Server sends if ClientHello.cipher_suites has TLS_FALLBACK_SCSV and
                                                    highest protocol version supported by Server is higher than ClientHello.client_version
                                    RFC7507
                                    Class Error

            missing_extension   send if received Handshake wihtout mandatory extension for  TLS version
                                                                                            other negotiated parameters
                                Class Error

            unsupported_extension   send if received    Handshake with prohibited extension
                                                        extensions in   ServerHello not offered in ClientHello
                                                                        Certificate not offered in CertificateRequest
                                    Class Error

            unrecognized_name   Server sends if no Server name can be found from server_name ClientHello
                                RFC6066
                                Class Error

            bad_certificate_status_response Client sends if received status_request has invalid OCSP
                                            RFC6066
                                            Class Error

            unknown_psk_identity    Server  may send if PSK key establishment is desired and
                                                        no acceptable PSK identity is provided by Client
                                            may not sent if invalid PSK identity
                                    Class Error

            certificate_required    Server sends if Client certificate is desired and
                                                    none was provided
                                    Class Error

            no_application_protocol Server sends if all Client application_layer_protocol_negotiation protocols are not supported
                                    RFC7301
                                    Class Error

    Middlebox   if  terminating a TLS connection
                    then    behave as compliant TLS Server to original Client
                                                    Client to original Server
                            have certificate which the client is willing to accept
                            verify original Server Certificate
                            generate own    ClientHello with parameters it understands
                                            random in ServerHello

                if  forwarding ClientHello parameters it does not understand
                    then    process no messages beyond ClientHello
                            forward all subsequent traffic unmodified

    FullConnection Test Vectors https://tools.ietf.org/html/rfc8448

RFC8017

    MGF1   mask generation function
           mask = MGF(mgfSeed, maskLen)
           mgfSeed  seed from which mask is generated
           maskLen  octet length of mask
                    <= 2^32 hLen  else mask = "mask too long"
           T starts as empty octet string
           for counter from 0 to ceil(maskLen / hLen) - 1
               do  C = I2OSP (counter, 4)
                   T = T || Hash(mgfSeed || C)
           mask = leading maskLen octets of T

    I2OSP  Integer-to-Octet-String primitive
           X  = I2OSP(x, xLen)
              = X_1 X_2 ... X_xLen
              X_i = x_(xLen-i) for 1 <= i <= xLen
              octet length = xLen
           x  nonnegative integer to be converted
              < 256^xLen  else X = "integer too large"
              = x_(xLen-1) 256^(xLen-1) +
                x_(xLen-2) 256^(xLen-2) + ... +
                x_1        256^1        +
                x_0        256^0
              x_i = a digit from x represented in base 256
                  >= 0
                  <  256
           if x < 256^(xLen-1)
              then one or more leading x_i will be zero

    OS2IP  Octet-String-to-Integer primitive
           x  = OS2IP(X)
              nonnegative integer
           X_1 X_2 ... X_xLen  = the octets of X from first to last
           x_(xLen-i)          = integer value of octet X_i for 1 <= i <= xLen
           x = x_(xLen-1) 256^(xLen-1) +
               x_(xLen-2) 256^(xLen-2) + ... +
               x_1        256^1        +
               x_0        256^0

    RSAEP  c = RSAEP((n,e), m)
             = m^e mod n
           (n,e) valid RSA public key
           m     message representative
                 >= 0  else c = "message representative out of range"
                 <  n  else c = "message representative out of range"

    RSADP  m = RSADP(K, c)
             < n
           K valid RSA public key
           c ciphertext representative
             >= 0  else m = "message representative out of range"
             <  n  else m = "ciphertext representative out of range"
           if  K = (n, d)
               then m = c^d mod n
           if  K = (p, q, dP, dQ, qInv) and a possibly empty sequence of triplets (r_i, d_i, t_i), i = 3, ..., u
               then m_1 = c^dP mod p
                    m_2 = c^dQ mod q
                    if u > 2
                       then m_i = c^(d_i) mod r_i, i = 3, ..., u
                    h = (m_1 - m_2) * qInv mod p
                    m = m_2 + q * h
                    if u > 2
                       then R = r_1 and for i = 3 to u
                                         do R = R * r_(i-1)
                                            h = (m_i - m) * t_i mod r_i
                                            m = m + R * h
    RSASP1  s = RSASP1(K, m)
              < n
            m message representative
              >= 0  else s = "message representative out of range"
              <  n  else s = "message representative out of range"
            K valid RSA public key
            if  K = (n, d)
                then s = m^d mod n
            if  K = (p, q, dP, dQ, qInv) and a possibly empty sequence of triplets (r_i, d_i, t_i), i = 3, ..., u
                then  s_1 = m^dP mod p
                      s_2 = m^dQ mod q
                      If u > 2
                         then s_i = m^(d_i) mod r_i, i = 3, ..., u
                      h = (s_1 - s_2) * qInv mod p
                      s = s_2 + q * h
                      if u > 2
                         then R = r_1 and for i = 3 to u
                                              do R = R * r_(i-1)
                                                 h = (s_i - s) * t_i mod r_i
                                                 s = s + R * h
    RSAVP1  m = RSAVP1((n,e), s)
              = s^e mod n
            (n,e) valid RSA public key
            s signature representative
              >= 0  else m = "signature representative out of range"
              <  n  else m = "signature representative out of range"

    RSAES-OAEP-ENCRYPT  C = RSAES-OAEP-ENCRYPT((n,e), M, L)

                        (n,e)  recipient's RSA public key
                        k  octet length of n

                        M  message to be encrypted
                           octet length  = mLen
                                        <= k - 2*hLen - 2     else C = "message too long"

                        L  optional label to be associated with the message
                           = emptyString  if L is not provided
                           octet length < limit of Hash input else C = "label too long"

                        lHash  = Hash(L)
                               octet length = hLen

                        if L = emptyString
                           then lHash = (0x)da39a3ee 5e6b4b0d 3255bfef 95601890 afd80709              ---> look --->                                                                        if Hash = SHA-1
                                        (0x)e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855                                                                         if Hash = SHA-256
                                        (0x)38b060a7 51ac9638 4cd9327e b1b1e36a 21fdb711 14be0743 4c0cc7bf 63f6e1da 274edebf e76f65fb d51ad2f1 4898b95b                                     if Hash = SHA-384
                                        (0x)cf83e135 7eefb8bd f1542850 d66d8007 d620e405 0b5715dc 83f4a921 d36ce9ce 47d0d13c 5d85f2b0 ff8318d2 877eec2f 63b931bd 47417a81 a538327a f927da3e if Hash = SHA-512

                        PS  padding string
                            value = 0
                            octet length = k - mLen - 2*hLen - 2
                                         = may be 0

                        DB  = lHash || PS || 0x01 || M
                            octet length = k - hLen - 1

                        seed  = random bits
                              octet length = hLen

                        dbMask      = MGF(seed, k - hLen - 1)
                        maskedDB    = DB xor dbMask
                        seedMask    = MGF(maskedDB, hLen)
                        maskedSeed  = seed xor seedMask
                        EM          = 0x00 || maskedSeed || maskedDB
                                    octet length = k
                        m = OS2IP(EM)
                        c = RSAEP ((n,e), m)
                        C = I2OSP (c, k)
                        _________________________________________________________
                        |                        +----------+------+--+-------+ |
                        |                   DB = |  lHash   |  PS  |01|   M   | |
                        |                        +----------+------+--+-------+ |
                        |                                       |               |
                        |             +----------+              |               |
                        |             |   seed   |              |               |
                        |             +----------+              |               |
                        |                   |                   |               |
                        |                   |-------> MGF ---> xor              |
                        |                   |                   |               |
                        |          +--+     V                   |               |
                        |          |00|    xor <----- MGF <-----|               |
                        |          +--+     |                   |               |
                        |            |      |                   |               |
                        |            V      V                   V               |
                        |          +--+----------+----------------------------+ |
                        |    EM =  |00|maskedSeed|          maskedDB          | |
                        |          +--+----------+----------------------------+ |
                        |_______________________________________________________|


    RSAES-OAEP-DECRYPT  M  = RSAES-OAEP-DECRYPT(K, C, L)
                           message string
                           octet length  = mLen
                                        <= k - 2hLen - 2
                        K  recipient's RSA private key
                        k  = octet length of n
                           >= 2*hLen + 2     else M = "decryption error"
                        C  ciphertext to be decrypted
                           octet length = k else M = "decryption error"
                        L  optional label
                           = emptyString  if L is not provided
                           octet length < limit of Hash input    else M = "decryption error"
                        c = OS2IP(C)
                        m = RSADP(K,c)
                            if m = "ciphertext representative out of range"
                               then M = "decryption error"
                        EM = I2OSP(m,k)
                           octet length = k
                        lHash = Hash(L)
                              octet length = hLen
                        Y || maskedSeed || maskedDB = EM
                        Y           octet length = 1
                        maskedSeed  octet length = hLen
                        maskedDB    octet length = k - hLen - 1
                        seedMask = MGF(maskedDB, hLen)
                        seed     = maskedSeed xor seedMask
                        dbMask   = MGF(seed, k - hLen - 1)
                        DB       = maskedDB xor dbMask
                        lHash' || PS || 0x01 || M = DB
                        lHash'  octet length = hLen
                        PS      = 0
                                octet length = variable
                                             = may be 0
                        if octet with value = 0x01 does not separate PS from M   or
                           lHash does not equal lHash'                           or
                           Y = nonzero
                           then M = "decryption error"
                           vulnerable to timing attack, make sure oponent cannot distinguish different error conditions

    RSAES-PKCS1-V1_5-ENCRYPT    C  = RSAES-PKCS1-V1_5-ENCRYPT((n,e), M)
                                   ciphertext
                                   octet length = k
                                (n,e)   recipient's RSA public key
                                k = octet length of n
                                M  message to be encrypted
                                   octet length  = mLen
                                                <= k - 11     else C = "message too long"
                                PS  padding string
                                    value  = random bits
                                    length = k - mLen - 3
                                           >= 8
                                EM = 0x00 || 0x02 || PS || 0x00 || M
                                   octet length = k
                                m = OS2IP(EM)
                                c = RSAEP((n,e), m)
                                C = I2OSP (c, k)
                                  octet length = k

    RSAES-PKCS1-V1_5-DECRYPT    M  = RSAES-PKCS1-V1_5-DECRYPT(K, C)
                                   octet length <= k - 11
                                K  recipient's RSA private key
                                C  ciphertext to be decrypted
                                   octet length = k  else M = "decryption error"
                                k  = octet length of n
                                  >= 11         else M = "decryption error"
                                c  = OS2IP (C)
                                m  = RSADP ((n, d), c)
                                   if m = "ciphertext representative out of range"
                                      then M = "decryption error"
                                EM = I2OSP (m, k)
                                   octet length = k
                                0x00 || 0x02 || PS || 0x00 || M = EM
                                if EM first  octet != 0x00                    or
                                      second octet != 0x02                    or
                                      has no 0x00 octet separating PS from M  or
                                   PS octet length < 8
                                   then M = "decryption error"
                                   vulnerable to timing attack, make sure oponent cannot distinguish different error conditions

    RSASSA-PSS-SIGN     S  = RSASSA-PSS-SIGN(K, M)
                           octet length = k
                        k       = octet length of n
                        modBits = bit   length of n
                        K  signer's RSA private key
                        M  message to be signed
                        EM = EMSA-PSS-ENCODE (M, modBits - 1)
                           octet length = ceil ((modBits - 1)/8)
                                        = k-1  if modBits-1 is     divisible by 8
                                        = k    if modBits-1 is not divisible by 8
                           if EM = "message too long"
                              then S = "message too long"
                           if EM = "encoding error"
                              then S = "encoding error"
                        m = OS2IP (EM)
                          octet length < modBits
                        s = RSASP1 (K, m)
                        S = I2OSP (s, k)

    RSASSA-PSS-VERIFY   voi = RSASSA-PSS-VERIFY ((n,e), M, S)
                        (n,e)  signer's RSA public key
                        M  message whose signature is to be verified
                        S  signature to be verified
                           octet length = k else voi = "invalid signature"
                        k       = octet length of n
                        modBits = bit   length of n
                        s = OS2IP (S)
                        m = RSAVP1 ((n, e), s)
                            if m = "signature representative out of range"
                               then voi = "invalid signature"
                        EM = I2OSP (m, emLen)
                           octet length = emLen = ceil ((modBits - 1)/8)
                                        = k-1  if modBits-1 is     divisible by 8
                                        = k    if modBits-1 is not divisible by 8
                           if EM = "integer too large"
                              then voi = "invalid signature"
                        Result = EMSA-PSS-VERIFY (M, EM, modBits - 1)
                        if Result = "consistent" then voi =   "valid signature"
                                                 else voi = "invalid signature"

    RSASSA-PKCS1-V1_5-SIGN  S  = RSASSA-PKCS1-V1_5-SIGN (K, M)
                               octet length = k
                            k  = octet length of n
                            K  signer's RSA private key
                            M  message to be signed
                            EM = EMSA-PKCS1-V1_5-ENCODE (M, k)
                               octet length = k
                               if EM = "message too long"
                                  then S = "message too long" and stop
                               if EM = "intended encoded message length too short"
                                  then S = "RSA modulus too short"
                            m = OS2IP (EM)
                            s = RSASP1 (K, m)
                            S = I2OSP (s, k)

    RSASSA-PKCS1-V1_5-VERIFY    S  = RSASSA-PKCS1-V1_5-VERIFY ((n,e), M, S)
                                   signature to be verified
                                   octet length = k else S = "invalid signature"
                                (n,e) signer's RSA public key
                                M     message whose signature is to be verified
                                k = octet length of n
                                s = OS2IP (S)
                                m = RSAVP1 ((n, e), s)
                                    if m = "signature representative out of range"
                                       then S = "invalid signature"
                                EM  = I2OSP (m, k)
                                    octet length = k
                                    if EM = "integer too large"
                                       then S = "invalid signature"
                                EM' = EMSA-PKCS1-V1_5-ENCODE (M, k)
                                    octet length = k
                                  if EM' = "message too long"
                                     then S = "message too long" and stop
                                  if EM' = "intended encoded message length too short"
                                     then S = "RSA modulus too short"
                                if EM = EM' then S =   "valid signature"
                                            else S = "invalid signature"

    EMSA-PSS-ENCODE     EM  = EMSA-PSS-ENCODE (M, emBits)
                            octet length  = emLen = ceil (emBits/8)
                                         >= hLen + sLen + 2      else EM = "encoding error"
                        M   message to be encoded
                            octet length < limit of Hash input   else EM = "message too long"
                        emBits  max bit length of the integer OS2IP(EM)
                                >= 8hLen + 8sLen + 9
                        mHash  = Hash(M)
                               octet length = hLen
                        salt   random octet string
                               octet length = sLen
                               = emptyString  if sLen = 0
                        M'  = (0x)00 00 00 00 00 00 00 00 || mHash || salt
                            octet length = 8 + hLen + sLen
                        H   = Hash(M')
                            octet length = hLen
                        PS  = 0
                            octet length = emLen - sLen - hLen - 2
                                         = may be 0
                        DB  = PS || 0x01 || salt
                            octet length =  emLen - hLen - 1
                        dbMask    = MGF(H, emLen - hLen - 1)
                        maskedDB  = DB xor dbMask
                                  set leftmost 8*emLen - emBits bits of
                                      leftmost octet = 0
                        EM = maskedDB || H || 0xbc

    EMSA-PSS-VERIFY     coi = EMSA-PSS-VERIFY (M, EM, emBits)

                        M   message to be verified
                            octet length < limit of Hash input  else coi = "inconsistent"

                        EM  encoded message
                            octet length  = emLen = ceil(emBits/8)
                                         >= hLen + sLen + 2     else coi = "inconsistent"
                            rightmost octet = 0xbc              else coi = "inconsistent"

                        emBits  max bit length of the integer OS2IP(EM)
                                >= 8hLen + 8sLen + 9

                        mHash   = Hash(M)
                                octet length = hLen

                        maskedDB = leftmost emLen - hLen - 1 octets of EM
                        H        = next hLen octets                 of EM

                        if leftmost 8*emLen - emBits bits of
                           leftmost octet in maskedDB != 0
                           then coi = "inconsistent"
                        dbMask = MGF(H, emLen - hLen - 1)
                        DB     = maskedDB xor dbMask
                               set leftmost 8*emLen - emBits bits of
                                   leftmost octet = 0

                        if emLen - hLen - sLen - 2 leftmost octets != 0 or
                           emLen - hLen - sLen - 1 position octet  != 1      leftmost position is "position 1"
                           then coi = "inconsistent"

                        salt = last sLen octets of DB
                             octet length = sLen

                        M'   = (0x)00 00 00 00 00 00 00 00 || mHash || salt
                             octet length = 8 + hLen + sLen

                        H'   = Hash(M')
                             octet length = hLen

                        if H = H' then coi =   "consistent"
                                  else coi = "inconsistent"

    EMSA-PKCS1-v1_5-ENCODE  EM  encoded message
                                = EMSA-PKCS1-v1_5-ENCODE (M, emLen)
                                = 0x00 || 0x01 || PS || 0x00 || T
                                = "message too long"                            if M length >= Hash input length limit
                                = "intended encoded message length too short"   if emLen < tLen + 11

                            M      message to be encoded
                            emLen  octet length of EM
                                   >= tLen + 11

                            PS  = 0xff in each octet
                                octet length  = emLen - tLen - 3
                                              >= 8

                            T  = (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10    || H  if Hash = MD2
                                 (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10    || H  if Hash = MD5
                                 (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14             || H  if Hash = SHA-1
                                 (0x)30 2d 30 0d 06 09 60 86 48 01 65 03 04 02 04 05 00 04 1c || H  if Hash = SHA-224
                                 (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H  if Hash = SHA-256
                                 (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H  if Hash = SHA-384
                                 (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H  if Hash = SHA-512
                                 (0x)30 2d 30 0d 06 09 60 86 48 01 65 03 04 02 05 05 00 04 1c || H  if Hash = SHA-512/224
                                 (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 06 05 00 04 20 || H  if Hash = SHA-512/256
                               octets length = tLen

                            H  = Hash(M)

    RSAPublicKey ::= SEQUENCE
    {
        modulus           INTEGER,  -- n
        publicExponent    INTEGER   -- e
    }

    RSAPrivateKey ::= SEQUENCE
    {
        version           Version,
        modulus           INTEGER,  -- n
        publicExponent    INTEGER,  -- e
        privateExponent   INTEGER,  -- d
        prime1            INTEGER,  -- p
        prime2            INTEGER,  -- q
        exponent1         INTEGER,  -- d mod (p-1)
        exponent2         INTEGER,  -- d mod (q-1)
        coefficient       INTEGER,  -- (inverse of q) mod p    CRT coefficient q^(-1) mod p
        otherPrimeInfos   OtherPrimeInfos OPTIONAL
    }

    Version ::= INTEGER { two-prime(0), multi(1) }  (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})

    OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo

    OtherPrimeInfo ::= SEQUENCE
    {
        prime             INTEGER,  -- ri
        exponent          INTEGER,  -- di
        coefficient       INTEGER   -- ti
    }

    RSAPrivateKey  binary file  uses DER
                                Example  using hexadecimal representation

                                         data starts with      -------->         30 82 04 A3 02 01 ...

                                         RSAPrivateKey      TagType  SEQUENCE         = 30
                                                            Length in next 2 bytes    = 82
                                                            Length                    = 04 A3
                                         version            TagType  INTEGER          = 02
                                                            Length                    = 01
                                                            Value                     = 00
                                         modulus            TagType  INTEGER          = 02
                                                            Length in next 2 bytes    = 82
                                                            Length                    = 01 01
                                                            Value                     = 00 AC 28 1A 29 41 88 7E FB E6 4D 35 B0 6D B9 99 59 C4 51 8D 13 DC C0 60 F7 BF EC 25 2C 07 C8 CC DF 76 9A 0F 86 47 61 CF 63 E8 7A D3 01 91 1C 97 21 F7 79 36 50 06 BB 8D 36 2E D4 B9 34 36 66 A6 FA 4D F2 07 AF 2D 28 7F 43 3F E8 06 D9 11 61 F0 BD 8A DE 5D DA B0 D4 4D DE 83 51 14 F2 6A 3F 5E F6 E5 7F C5 5D EB E7 05 FA 45 EE 91 98 3D 95 EE 8D 06 DF 4E 68 BF 29 8C 35 48 85 95 37 17 DC 1F D6 81 35 9D ED 8C 2C EA A3 91 17 FE 27 C0 F5 68 74 88 2C 1E FB 75 63 00 FA FA 28 09 2A E9 EC 73 92 3C 36 68 E6 79 FB A4 25 ED 17 46 EA E9 F5 14 89 F2 57 C6 BC E6 41 9A 64 20 71 B6 B9 B7 0B 41 63 19 84 20 52 86 6E 14 1A BE 9B C9 81 01 82 5A DD 53 A5 31 C7 C7 7C DA 0B B5 08 C5 5D 9F DF A2 A9 08 D1 3C D5 DA CA 43 DA 47 E3 8B 8E B3 FC 6A 34 87 B1 30 7E 2F FC 61 92 EC EC CE 16 4E 12 73 01
                                         publicExponent     TagType  INTEGER          = 02
                                                            Length                    = 03
                                                            Value                     = 01 00 01
                                         privateExponent    TagType  INTEGER          = 02
                                                            Length in next 2 bytes    = 82
                                                            Length                    = 01 00
                                                            Value                     = 0E 97 9B 98 11 A0 F3 3A 80 CB DC 98 26 C4 CB 95 CB 49 2A 4F 1B B0 06 C8 19 31 77 F9 22 73 C7 C1 CD 38 C3 C6 1A F8 D4 6E 60 7F 40 B1 6A 4E 65 15 10 F7 EA 3D A0 44 77 74 B7 45 7A A9 4D 4F 28 2A 21 3F 39 9D 84 93 61 2E 1F 15 98 B6 FF 7D 30 BD B0 2E A6 FF E9 6B 25 6A 8D F0 EA 78 9D BE DF 5A C8 1B 2B 6C 89 99 5C 6D 59 4E 1E 73 2C 0D 30 5A 2D D1 F1 C0 79 2B 99 61 CE D2 DB D1 FE A8 BE DD F9 1D B5 42 67 35 78 B0 08 78 E6 72 D6 7D 1B 50 04 A5 D0 B3 AF 7D 86 F2 21 B1 C9 DC D7 54 26 0F 85 D9 0D 3E 1A 67 95 96 8D 11 62 2C A6 31 E8 38 06 F3 42 E7 7B 54 E8 FF CC 5F 23 6F BF 2C 7E F6 BA 07 BB 62 CC D3 30 68 44 70 D2 85 1B C0 AA 0C 3D 15 FE 28 C2 B8 86 A6 BD 33 6C F9 27 68 98 24 9D CD 77 1F D3 4B 4A 9F DF 03 23 5B 83 C2 C7 25 A6 3C D5 4A A0 F5 CD DF EC B0 3D F2 99 BD 2F 91
                                         prime1             TagType  INTEGER          = 02
                                                            Length in next 1 bytes    = 81
                                                            Length                    = 81
                                                            Value                     = 00 D7 A3 38 D0 3F CD 5A E4 68 4A 44 A9 69 5F 93 F2 09 CB AB 00 4C FA 1F 66 BC 7F 14 9B 27 38 03 13 7C 29 AA 3F 24 9F 6F 3B CF 1B 33 48 80 78 0D B0 AA 1A 39 50 22 8A 7F F7 9F 94 17 29 09 93 2F B2 A3 77 39 D1 43 92 FF 72 90 9B 30 71 42 9A B0 02 3B 05 E1 4A BF 78 76 6C 59 04 56 41 31 04 EB 25 C4 81 37 32 EF 94 61 F0 7C B2 DC DB 50 74 4A 58 BC 1E 29 12 9E EF 29 3A A5 AC 44 85 8C 17 24 6D
                                         prime2             TagType  INTEGER          = 02
                                                            Length in next 1 bytes    = 81
                                                            Length                    = 81
                                                            Value                     = 00 CC 61 63 C5 DA B0 36 DF 51 AF 09 2F 96 1F E8 A4 99 1D 0F AD 8A E1 F8 AE E4 F3 67 01 B8 0F 4C E3 08 D6 44 C0 B2 3C 2D A0 7D 62 01 32 F6 63 B5 0D 36 35 43 90 25 88 E9 43 D6 F4 65 DF 5C AB E8 6E ED D9 67 9C 06 CE DB 89 7E 8D D9 5A 4C 4D 91 D6 1C E5 C4 37 DD 25 2F 2A 7E E5 51 A2 E3 EB BE 23 A4 CF 5B 6E BB 52 BC 35 63 A3 3B 52 25 12 D7 E6 9B 7C 60 86 CA 7F CB 46 6A E9 F6 0E 4E 80 E4 65
                                         exponent1          TagType  INTEGER          = 02
                                                            Length in next 1 bytes    = 81
                                                            Length                    = 80
                                                            Value                     = 5A 1A 21 8B 22 9D B3 F4 EC 7E DB E1 CD DD D9 FB B0 8C 21 8F A6 9A 7C B4 78 DE C0 C5 73 C5 BB C3 50 86 38 54 DA 00 A4 81 E1 30 04 65 AF 08 7A EF EE A3 B6 7E FD 6F D1 B8 AE 3D 3A D0 32 E8 05 6E 27 4F 92 21 16 93 3D 99 A9 42 AF 23 24 29 6E 92 00 07 9C F3 96 BD C6 FD CE D4 39 16 54 5D 31 C4 3E 2F 9F D8 F0 B2 97 99 DD 00 FF B7 C4 0E 53 62 70 78 49 C1 36 17 C8 AA 70 BF 62 82 4A DF 00 A1
                                         exponent2          TagType  INTEGER          = 02
                                                            Length in next 1 bytes    = 81
                                                            Length                    = 80
                                                            Value                     = 0B 11 57 12 D6 D5 E6 12 CF DC 97 B5 C0 FE 77 5D BA 80 ED 61 6B 7C F3 37 9D 64 64 F6 9D DE 0E 3E D9 32 A9 44 7A 22 72 22 17 C8 1F E2 7F 9F 44 A5 B3 82 CC E6 D8 71 82 98 4E E2 AB 45 9E 42 1C F3 2C E4 32 0D 2B FD 35 BC 4B 63 29 1B 0F B8 BF A6 05 A8 97 A8 A2 CC 29 B2 B6 6E 7A AE 44 83 76 A7 7D 7C 51 2A 3C F0 AD 0A 83 1B CA D1 96 FA 5F 40 B8 B8 D2 8D 5A 17 F3 8D 1B AB 11 CD 12 89 3E 55
                                         coefficient        TagType  INTEGER          = 02
                                                            Length in next 1 bytes    = 81
                                                            Length                    = 81
                                                            Value                     = 00 BE CE 82 86 E7 AB DC 7F 45 B8 CB D8 A9 57 B1 FA DA E6 70 37 9F F7 E4 77 1A 5D 88 37 EF 3A C1 12 2C 72 C2 09 5B 3B 10 A2 D1 FD 22 32 06 6A 42 5E A4 9B 5B D7 7D E8 19 B9 D0 22 1F DE D2 50 18 A8 55 44 68 5E 99 9F 55 BE 65 41 A2 F4 88 58 1E 24 66 30 3C 79 1D 82 0F 18 18 69 24 F4 9C B9 EB 53 AA C1 FE C3 78 4A F7 A4 47 9F C9 20 CE 01 4A C4 31 E9 F1 02 06 62 74 E6 51 CF 7D 9A 45 FF DB 94
    BER    Basic         Encoding Rules
    DER    Distinguished Encoding Rules
           subset of BER
           uses TLVformat
    CER    Canonical     Encoding Rules
    OER    Octet         Encoding Rules
    PER    Packed        Encoding Rules
    XER    XML           Encoding Rules
    E-XER  Extended XER
    JER    JSON          Encoding Rules

    TLVformat  = Tag || Length || Value
               || means concatenation
               Tag     = Class || Form || Value
                       size = 8 bit
                       Class   = 0 UNIVERSAL
                               = 1 APPLICATION
                               = 2 contex-defined
                               = 3 PRIVATE
                               size = 2 bit
                       Form    = 0 primitive
                               = 1 constructed
                               size = 1 bit
                       Value   size = 5 bit
                       ---------------------------------------------------------------------------
                       | TagType              Class        Form           Class || Form || Value |
                       | BIT STRING           UNIVERSAL    Primitive      00000011 = 03          |
                       | BOOLEAN              UNIVERSAL    Primitive      00000001 = 01          |
                       | INTEGER              UNIVERSAL    Primitive      00000010 = 02          |
                       | NULL                 UNIVERSAL    Primitive      00000101 = 05          |
                       | OBJECT IDENTIFIER    UNIVERSAL    Primitive      00000110 = 06          |
                       | OCTET STRING         UNIVERSAL    Primitive      00000100 = 04          |
                       | BMPSTRING            UNIVERSAL    Primitive      00011110 = 1E          |
                       | IA5STRING            UNIVERSAL    Primitive      00010110 = 16          |
                       | PrintableString      UNIVERSAL    Primitive      00010011 = 13          |
                       | TELETEXSTRING        UNIVERSAL    Primitive      00010100 = 14          |
                       | UTF8String           UNIVERSAL    Primitive      00001100 = 0C          |
                       | UTCTime              UNIVERSAL    Primitive      00010111 = 17          |
                       | GeneralizedTime      UNIVERSAL    Primitive      00011000 = 18          |
                       | SEQUENCE             UNIVERSAL    Constructed    00110000 = 30          |
                       | SEQUENCE OF          UNIVERSAL    Constructed    00110000 = 30          |
                       | SET                  UNIVERSAL    Constructed    00110001 = 31          |
                       | SET OF               UNIVERSAL    Constructed    00110001 = 31          |
                       ---------------------------------------------------------------------------

               Length  if size of TLVformat.Value < 128 bytes
                          then    ==========================
                                  |size of TLVformat.Value |
                                  --------------------------
                                  | 0  x  x  x  x  x  x  x |
                                  ==========================
                                  7 least significant bits define size in bytes of TLVformat.Value
                       if size of TLVformat.Value >= 128 bytes
                          then    =======================================
                                  |  number of bytes next  | size of TLVformat.Value
                                  ----------------------------------------------
                                  | 1  x  x  x  x  x  x  x | y  y  y  y  y ....
                                  =====================================
                                  7 least significant bits define size in bytes of size in bytes of TLVformat.Value
               Value   depends on assigned ASN.1
                       may be = Value
                       may be = Tag || Length || Value

SHA256  = SHA256(msg)
        msg  message to hash
             bit size =  l
                      >= 0
                      <  2^64
        l  bit size = 64

        M  = msg || pad
           pad bit value = 1 || 0...0 || l
               bit size  = 1 +    o    + 64
                         != 0
           bit size = multiple of 512
                      (l + 1 + o + 64) mod 512 = 0

        H  starting value = 6a09e667 bb67ae85 3c6ef372 a54ff53a 510e527f 9b05688c 1f83d9ab 5be0cd19
                            in hexadecimal
                          represents the first thirty-two bits of
                                     the fractional parts      of
                                     the square roots          of
                                     the first eight prime numbers
           changes value while M is hashed
           bit size = 8*32

        K  represents the first 32bits     of
                      the fractional parts of
                      the cube roots       of
                      the first 64 prime numbers
           = 428a2f98 71374491 b5c0fbcf e9b5dba5 3956c25b 59f111f1 923f82a4 ab1c5ed5
             d807aa98 12835b01 243185be 550c7dc3 72be5d74 80deb1fe 9bdc06a7 c19bf174
             e49b69c1 efbe4786 0fc19dc6 240ca1cc 2de92c6f 4a7484aa 5cb0a9dc 76f988da
             983e5152 a831c66d b00327c8 bf597fc7 c6e00bf3 d5a79147 06ca6351 14292967
             27b70a85 2e1b2138 4d2c6dfc 53380d13 650a7354 766a0abb 81c2c92e 92722c85
             a2bfe8a1 a81a664b c24b8b70 c76c51a3 d192e819 d6990624 f40e3585 106aa070
             19a4c116 1e376c08 2748774c 34b0bcb5 391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3
             748f82ee 78a5636f 84c87814 8cc70208 90befffa a4506ceb bef9a3f7 c67178f2
             in hexadecimal
           bit size = 64*32

        W  bit size = 64*32

        each 512bit of M is refered as M2[j]
        each 512bit of W is refered as W2[j]
        each  32bit of M is refered as  M[i]
        each  32bit of W is refered as  W[i]
        each  32bit of H is refered as  H[i]
        each  32bit of K is refered as  K[i]

        M is divided in N 512bit blocks

        for j = 0 to N-1 do
            W2[0] = M2[j]
            for i = 16 to 63 do
                W[i] = o1SH(W[i- 2]) + W[i- 7] +
                       o0SH(W[i-15]) + W[i-16]
            initialize variables a,b,c,d,e,f,g,h each 32bit in size
             a = H[0]
             b = H[1]
             c = H[2]
             d = H[3]
             e = H[4]
             f = H[5]
             g = H[6]
             h = H[7]
            for i = 0 to 63 do
                initialize variables t1,t2 each 32bit in size
                 t1 = h + s1SH(e) + chSH(e,f,g) + K[i] + W[i]
                 t2 = s0SH(a) + maSH(a,b,c)
                h = g
                g = f
                f = e
                e = d + t1
                d = c
                c = b
                b = a
                a = t1 + t2
            H[0] = H[0] + a
            H[1] = H[1] + b
            H[2] = H[2] + c
            H[3] = H[3] + d
            H[4] = H[4] + e
            H[5] = H[5] + f
            H[6] = H[6] + g
            H[7] = H[7] + h
        output H

        internal functions  chSH(x,y,z) = (x&y) ^ ((~x)&z)
                            maSH(x,y,z) = (x&y) ^ (  x &z) ^ (y&z)
                            s0SH(x)     = rotR(x, 2) ^ rotR(x,13) ^ rotR(x,22)
                            s1SH(x)     = rotR(x, 6) ^ rotR(x,11) ^ rotR(x,25)
                            o0SH(x)     = rotR(x, 7) ^ rotR(x,18) ^ (x >>  3)
                            o1SH(x)     = rotR(x,17) ^ rotR(x,19) ^ (x >> 10)
                            rotR(x,m)   = (x >> m) | (x << 32-m)

                            &  = bitwise    AND     operation
                            |  = bitwise     OR     operation
                            ^  = bitwise complement operation
                            << = left  shift        operation
                            >> = right shift        operation

                            operate on 32bit variables
                            addition operator is performed modulo 2^32

ACME
    RFC8555
    Automatic Certificate Management Environment
    protocol for Web PKI Certificates
    automates process of Certificate verification
                                     issuance
                                     revocation
    used by Applicant    will be the ACME client    will be the Client
            CA           will be the ACME server    will be the Server

    communications between Client and Server use HTTPS
                                                 JWS
                   via HTTP are UTF-8 encoded

    steps    Client  establishes new account with Server
                     proves control of identifier
                     issues Certificate
                     fetches updated certificate some time after issuance
                     +----------------------+---------------------------------------+---------------+
                     | Action               | Request                               | Response      |
                     +----------------------+---------------------------------------+---------------+
                     | get directory        | GET  directory                        | 200           |
                     | get nonce            | HEAD newNonce                         | 200           |
                     | create account       | POST newAccount                       | 201 -> account|
                     | submit order         | POST newOrder                         | 201 -> order  |
                     | fetch challenges     | POST-as-GET order's authorization urls| 200           |
                     | respond to challenges| POST authorization challenge urls     | 200           |
                     | poll for status      | POST-as-GET order                     | 200           |
                     | finalize order       | POST order's finalize url             | 200           |
                     | poll for status      | POST-as-GET order                     | 200           |
                     | download certificate | POST-as-GET order's certificate url   | 200           |
                     +----------------------+---------------------------------------+---------------+
                         "->" = mnemonic for location header field pointing to created resource

    CertificateManagement   AccountCreation
                            OrderingCertificate
                            IdentifierAuthorization
                            CertificateIssuance
                            CertificateRevocation

    Resources   types  AccountReso        information about an account
                       OrderReso          account's requests to issue certificates
                       AuthorizationReso  account's authorization to act for an identifier
                       ChallengeReso      challenge to prove control of an identifier
                       CertificateReso    issued certificates
                       "directory"        must be provided by Server
                       "newNonce"         must be provided by Server
                       "newAccount"
                       "newOrder"
                       "revokeCert"
                       "keyChange"

                created by Server
                are accesed using URLs
                URLs are connected by linkRelations

                linkRelations  RFC8288
                               "up"    used with ChallengeReso
                                       indicates AuthorizationReso to which a challenge belongs
                                       used with media types from CertificateReso

                               "index" present on all resources other than Directory
                                       indicates the URL of Directory

                requests for Resources different to "newAccount" and "revokeCert" have "kid" in "protected"

                if Server receives GET request for resources different to "newNonce" or "directory"
                   then Server return status code 405 (Method Not Allowed)
                                      error type "malformed"

                if Client request resource from Server
                   then Client sends POST request with JWS "payload" = zero-length octet string
                        Server authenticates Client and verifies any access control rules
                        if authentication fails
                           then Server returns status code 405 (Method Not Allowed)
                                               error type "malformed"

                Server rate limits resource creation returning  error type "urn:ietf:params:acme:error:rateLimited"
                                                     may return HTTP Retry-After indicating when current request may succeed again
                                                                "detail" human-readable cause of error
                                                                Link header field  pointing to documentation about the specific rate limit that was hit
                                                                                   with "help" type
                                                                                   RFC8288
                ResourcesRelationships  map                              directory
                                                                             |
                                                                             +--> newNonce
                                                                             |
                                                 +----------+----------+-----+-----+------------+
                                                 |          |          |           |            |
                                                 |          |          |           |            |
                                                 V          V          V           V            V
                                            newAccount   newAuthz   newOrder   revokeCert   keyChange
                                                 |          |          |
                                                 |          |          |
                                                 V          |          V
                                              account       |        order --+--> finalize
                                                            |          |     |
                                                            |          |     +--> cert
                                                            |          V
                                                            +---> authorization
                                                                      | ^
                                                                      | | "up"
                                                                      V |
                                                                    challenge
    Directory  provided by Server
               Server allows GET and POST requests for Directory resources

               fields  "newNonce"    has URL that returns new nonce
                       "newAccount"  has URL that returns new account
                       "newOrder"    has URL that returns new order
                       "newAuthz"    has URL that returns new authorization
                                     ommited if not supported
                       "revokeCert"  has URL that returns Revoke certificate
                       "keyChange"   has URL that returns Key change
                       "meta"  JSON object
                               items   "termsOfService"  optional
                                                         string URL
                                                         URL returns the terms of service
                                                         if Server rejects newAccount with    "termsOfServiceAgreed" = false or
                                                                                      without "termsOfServiceAgreed"
                                                            then "termsOfService" is included

                                       "website"         optional
                                                         string URL HTTP or HTTPS
                                                         URL returns more information about ACME Server

                                       "caaIdentities"   optional
                                                         array of string
                                                         each string = ASCII sequence as "Issuer Domain Name" in CAA issue or
                                                                                                                 issuewild property tag
                                                                       hostnames that Server recognizes as referring to itself
                                                                                 for CAA record validation    RFC6844
                                                                                                configuration
                                       "externalAccountRequired"  optional
                                                                  boolean
                                                                  if = true  then all newAccount requests need "externalAccountBinding"
                                                                     else Server may return error type "externalAccountRequired"

               Server of both ACME and Web may have Web  path "example.com/frontpage"
                                                    ACME path "example.com/acme" for Directory
                      of only ACME         may have ACME path "example.com/"     for Directory

               example  HTTP/1.1 200 OK
                        Content-Type: application/json
                        {
                          "newNonce": "https://example.com/acme/new-nonce",
                          "newAccount": "https://example.com/acme/new-account",
                          "newOrder": "https://example.com/acme/new-order",
                          "newAuthz": "https://example.com/acme/new-authz",
                          "revokeCert": "https://example.com/acme/revoke-cert",
                          "keyChange": "https://example.com/acme/key-change",
                          "meta":
                           {
                             "termsOfService": "https://example.com/acme/terms/2017-5-30",
                             "website": "https://www.example.com/",
                             "caaIdentities": ["example.com"],
                             "externalAccountRequired": false
                           }
                        }

    Nonce  if Client needs new nonce
              then case1    Client sends   HEAD request to URL of "newNonce"
                            Server returns Replay-Nonce header with new nonce
                                           may have status code 200 (OK)
                                           Cache-Control header with "no-store"
                   case2    Client sends   GET request to URL of "newNonce"
                            Server returns Replay-Nonce header with new nonce
                                           status code 204 (No Content)
                                           Cache-Control header with "no-store"

                   example    HEAD /acme/new-nonce HTTP/1.1
                              Host: example.com

                              HTTP/1.1 200 OK
                              Replay-Nonce: oFvnlFP1wIhRlYS2jTaXbA
                              Cache-Control: no-store
                              Link: <https://example.com/acme/directory>;rel="index"

           Server allows GET and POST requests to URL of "newNonce"
                  provides nonce in HTTP Replay-Nonce header
                                 with unique value
                  may provide nonce in error responses
                  verifies received "nonce" was created by Server

           Client "protected" always has "nonce" from HTTP Replay-Nonce sent by Server
                  ignores invalid HTTP Replay-Nonce sent by Server

           if "nonce" has appeared in previous request or
                      not present in "protected"
              then Server returns status code 400(Bad Request)
                                  error type "urn:ietf:params:acme:error:badNonce"
                                  Replay-Nonce with new valid nonce
                   Client may retry previous  query using only that new nonce
                              try   different query using      that new nonce

           Replay-Nonce header
               uses base64url encoding
                        using URL- and filename-safe character set defined in Section 5 of RFC4648
                        all trailing '=' characters omitted (as permitted by Section 3.2)
                        has no line breaks
                               whitespace
                               other additional characters
                        encoding of empty octet sequence is the empty string
               should not be in HTTP request messages
               ABNF  base64url    = ALPHA / DIGIT / "-" / "_"
                     Replay-Nonce = 1*base64url

    AccountReso  "status"                 of this account
                                          = "valid"
                                            "deactivated"    client-initiated deactivation
                                            "revoked"        server-initiated deactivation

                 "orders"                 string URL
                                          cannot be updated by Client
                                          URL returns OrdersList submitted by this account
                                              accesed with POST-as-GET request

                 "contact"                optional
                                          array of string URL
                                          used by Server to contact Client for issues related to this account
                                          example    Server notifes Client about server-initiated revocation
                                                                                 certificate expiration
                 "termsOfServiceAgreed"   optional
                                          boolean
                                          cannot be updated by Client

                 "externalAccountBinding" optional
                                          object
                                          cannot be updated by Client
                                          used to associate AccountReso with non-ACME account such as CA customer database
                                          if inside newAccount request
                                             then account holder approves to bind non-ACME account to
                                                                                  ACME     account
                 example  {
                            "status": "valid",
                            "contact": [ "mailto:cert-admin@example.org",
                                         "mailto:admin@example.org" ],
                            "termsOfServiceAgreed": true,
                            "orders": "https://example.com/acme/orders/rzGoeA"
                          }

                 states                valid
                                         |
                                         |
                             +-----------+-----------+
                      Client |                Server |
                     deactiv |                revoke |
                             V                       V
                        deactivated               revoked

    OrdersList  JSON object with "orders"
                has array of string URL
                each URL returns OrderReso made by account
                may not include invalid OrdersReso
                may include pending OrdersReso
                may be incomplete
                may be with Link header field with "next" link relation indicating where further entries can be acquired

                example  HTTP/1.1 200 OK
                         Content-Type: application/json
                         Link: <https://example.com/acme/directory>;rel="index"
                         Link: <https://example.com/acme/orders/rzGoeA?cursor=2>;rel="next"
                         {
                           "orders": [ "https://example.com/acme/order/TOlocE8rfgo",
                                       "https://example.com/acme/order/4E16bbL5iSw",
                                       "https://example.com/acme/order/neBHYLfw0mg" ]
                         }

    OrderReso  represents request for certificate
               tracks progress of order

               "status"       = "pending"
                                "ready"
                                "processing"
                                "valid"
                                "invalid"

               "expires"      string
                              timestamp for when this order becomes invalid
                              format RFC3339
                              optional except if "status" = "pending"
                                                            "valid"
               "identifiers"  array of object
                              immutable once set
                              identifier that the order pertains to
                                         "type"  = "dns"  see registry defined in Section 9.7.7 for any others
                                         "value" identifier itself
               "notBefore"       optional
                                 string
                                 requested value of notBefore field in certificate
                                 format RFC3339

               "notAfter"        optional
                                 string
                                 requested value of notAfter field in certificate
                                 format RFC3339

               "error"           optional
                                 object
                                 error that occurred while processing order
                                 structured as problem document RFC7807

               "authorizations"  array of string URL
                                 immutable once set
                                 if "pending" OrdersReso
                                    then this has authorizations to complete before requested certificate can be issued
                                                  unexpired authorizations that were completed for "identifiers"
                                 if "valid" or "invalid" OrdersReso
                                    then this has Authorization completed
                                 there may not be a 1:1 relationship between  "identifiers"    and
                                                                              "authorizations"
                                 each URL returns AuthorizationReso
                                          requested using POST-as-GET
                                 authorizations required are dictated by Server policy
                                 if CA allows multiple OrderReso to be fulfilled based on one authorization
                                    then it may reflect that authorization in all OrderReso
                                 some may already be valid because Client completed authorization in another OrderReso
                                                                   Client previously pre-authorized the identifier
                                                                   Server authorized Client using external account
                                 Client may read "status"of OrderReso to determine if more "authorizations" need completion

               "finalize"        string URL
                                 Client POST a CSR to this URL after all "authorizations" are satisfied

               "certificate"     optional
                                 string URL
                                 populated by Server after all "authorizations" are satisfied
               example  {
                          "status": "valid",
                          "identifiers": [ { "type": "dns", "value": "www.example.org" },
                                           { "type": "dns", "value": "example.org"     }  ],
                          "expires":   "2016-01-20T14:09:07.99Z",
                          "notBefore": "2016-01-01T00:00:00Z",
                          "notAfter":  "2016-01-08T00:00:00Z",
                          "authorizations": [ "https://example.com/acme/authz/PAniVnsZcis",
                                              "https://example.com/acme/authz/r4HqLzrSrpI"  ],
                          "finalize":    "https://example.com/acme/order/TOlocE8rfgo/finalize",
                          "certificate": "https://example.com/acme/cert/mAt3xBGaobw"
                        }

               states     pending --------------+
                             |                  |
                             | All authz        |
                             | "valid"          |
                             V                  |
                           ready ---------------+
                             |                  |
                             | Receive          |
                             | finalize         |
                             | request          |
                             V                  |
                         processing ------------+
                             |                  |
                             | Certificate      | Error or OrderReso expired or
                             | issued           | AuthorizationReso "expired" or "revoked" or "deactivated"
                             V                  V
                           valid             invalid

               Server that issues orders synchronously will never show "processing"

    AuthorizationReso  represents Server's authorization for account to represent this "identifier"

                       "identifier"  object
                                     that AccountReso is authorized to represent
                                     "type"  = "dns"
                                     "value" identifier itself
                                             as it would appear in Certificate
                                             format RFC5280 Section 7
                                             if begins with "xn--"
                                                then Server verifies format RFC5890

                       "status"      of this AuthorizationReso
                                     = "pending"
                                       "valid"
                                       "invalid"
                                       "deactivated"
                                       "expired"
                                       "revoked"
                                     Server that immediately deletes "expired" AuthorizationReso will never show "expired"

                       "expires"     optional except if this AuthorizationReso "status" = "valid"
                                     string
                                     timestamp when this AuthorizationReso becomes "invalid"
                                     format RFC3339

                       "challenges"  array of objects
                                     Client fulfills to prove possession of this "identifier"
                                     Server may consider one challenge sufficient
                                     has ChallengeReso that was validated if ChallengeReso   "valid"
                                                                failed    if ChallengeReso "invalid"

                       "wildcard"    = true  if created for newOrder with wildcardDomainName
                                                else "wildcard" is absent

                       example  {
                                  "status": "valid",
                                  "expires": "2015-03-01T14:09:07.99Z",
                                  "identifier": { "type": "dns",
                                                  "value": "www.example.org" },
                                  "challenges": [
                                    {
                                      "url": "https://example.com/acme/chall/prV_B7yEyA4",
                                      "type": "http-01",
                                      "status": "valid",
                                      "token": "DGyRejmCefe7v4NfDGDKfA",
                                      "validated": "2014-12-01T12:05:58.16Z"
                                    }
                                  ],
                                  "wildcard": false
                                }

                       states                pending --------------------+
                                                |                        |
                              Challenge failure |                        |
                                     or         |                        |
                                    Error       |  Challenge valid       |
                                      +---------+---------+              |
                                      |                   |              |
                                      V                   V              |
                                   invalid              valid            |
                                                          |              |
                                                          |              |
                                                          |              |
                                           +--------------+--------------+
                                           |              |              |
                                           |              |              |
                                    Server |       Client |   Time after |
                                    revoke |   deactivate |    "expires" |
                                           V              V              V
                                        revoked      deactivated      expired

    ChallengeReso  represents Server's offer to validate Client's possession of identifier in a specific way
                   contents depend on validation method
                   has no standard structure

                   "type"       string
                                    of challenge
                                    set by Server policy

                   "url"        string
                                to which response can be posted

                   "status"     string
                                of challenge
                                = "pending"
                                  "processing"
                                  "valid"
                                  "invalid"
                                if = "invalid" then Server may include "error" to help diagnose failure

                   "validated"  optional
                                string
                                set if "status" = "valid"
                                time at which Server validated Challenge
                                format RFC3339

                   "error"      optional
                                object
                                that occurred while Server was validating Challenge, if any
                                structured as problem document RFC7807
                                multiple errors can be indicated using "subproblems"
                                if incuded then "status" = "invalid"

                   states           pending
                                       |
                                       | Client responds to challenge
                                       | Server receives response
                                       V
                                   processing <-+
                                       |   |    | Server retries validation or
                                       |   |    | client retries request
                                       |   +----+
                                       |
                                       |
                           Successful  |   Failed
                           validation  |   validation
                             +---------+---------+
                             |                   |
                             V                   V
                           valid              invalid

    AccountCreation
        Client wants to create new AccountReso
               generates AKP
               POST to URL of "newAccount"
                    has JWS
                    "protected" has "jwk" and other fields shown in JWS
                    "payload"  "contact"                 optional
                                                         array of string
                                                         same meaning as "contact" of AccountReso
                                                         has no "mailto"  if "hfields" RFC6068 is present   or
                                                                             "to" has more than one "addr-spec"
                                                         "mailto" is supported by Server  if Server validates URLs
                                                         if URL has unsupported scheme
                                                            then Server returns error "unsupportedContact"
                                                                                error description
                                                                                types of URLs Server accepts
                                                         if URL has supported scheme and invalid value
                                                            then Server returns error "invalidContact"
                               "termsOfServiceAgreed"    optional
                                                         boolean
                                                         same meaning as "termsOfServiceAgreed" of AccountReso
                                                         Clients may not automatically agree
                                                                     require some user interaction for agreement
                                                         if = false  or not included and
                                                            Server requires agreement
                                                            then Server rejects newAccount requests
                               "onlyReturnExisting"      optional
                                                         boolean
                                                         allows Client to find AccountReso URL based on account key
                                                         if = true  and AccountReso already exist
                                                            then Server creates no new AccountReso
                                                         if = true  and AccountReso does not exist
                                                            then Server returns status code 400 (Bad Request)
                                                                                error type "urn:ietf:params:acme:error:accountDoesNotExist"
                               "externalAccountBinding"  optional
                                                         object
                                                         same meaning as "externalAccountBinding" of AccountReso
                                                         if not verified by Server
                                                            then Server does not reflect "externalAccountBinding" data in new AccountReso
                    "signature" uses privateKey of AKP

                    example  POST /acme/new-account HTTP/1.1
                             Host: example.com
                             Content-Type: application/jose+json
                             {
                               "protected": base64url({
                                 "alg": "ES256",
                                 "jwk": {...},
                                 "nonce": "6S8IqOGY7eL2lsGoTZYifg",
                                 "url": "https://example.com/acme/new-account"
                               }),
                               "payload": base64url({
                                 "termsOfServiceAgreed": true,
                                 "contact": [
                                   "mailto:cert-admin@example.org",
                                   "mailto:admin@example.org"
                                 ]
                               }),
                               "signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
                             }

        Server ignores unrecognized fields of received POST
                       example  if POST has "orders"
                                   then Server ignores it
               checks if "jwk" already exist
                         then returns  status code 200 (OK)
                                       Location header with URL of AccountReso with that "jwk"
                         else creates AccountReso
                              stores "jwk" to authenticate future requests
                              returns  status code 201 (Created)
                                       Location header with URL of AccountReso
                                       AccountReso
                                       example   HTTP/1.1 201 Created
                                                 Content-Type: application/json
                                                 Replay-Nonce: D8s4D2mLs8Vn-goWuPQeKA
                                                 Link: <https://example.com/acme/directory>;rel="index"
                                                 Location: https://example.com/acme/acct/evOfKhNU60wg
                                                 {
                                                   "status": "valid",
                                                   "contact": [ "mailto:cert-admin@example.org",
                                                                "mailto:admin@example.org"],
                                                   "orders": "https://example.com/acme/acct/evOfKhNU60wg/orders"
                                                 }
                                       then Client puts URL of AccountReso in "kid" of subsequent requests
    AccountUpdate
        Client wants to update AccountReso
               POST to URL of AccountReso
                    example  POST /acme/acct/evOfKhNU60wg HTTP/1.1
                             Host: example.com
                             Content-Type: application/jose+json
                             {
                               "protected": base64url({
                                 "alg": "ES256",
                                 "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                 "nonce": "ax5RnthDqp_Yf4_HZnFLmA",
                                 "url": "https://example.com/acme/acct/evOfKhNU60wg"
                               }),
                               "payload": base64url({
                                 "contact": [
                                   "mailto:certificates@example.org",
                                   "mailto:admin@example.org"
                                 ]
                               }),
                               "signature": "hDXzvcj8T6fbFbmn...rDzXzzvzpRy64N0o"
                             }
        if Server accepts account update
           then returns status code 200 (OK)
                        AccountReso

    ExternalAccountBinding
        Server binds new AccountReso to nonACMEaccount of nonACMEsystem
        steps  nonACMEsystem sends to Client
                                   MACkey         may be base64url encoded
                                   keyIdentifier  as ASCII string
                                   using some mechanism outside of ACME

               Client does newAccount request with "externalAccountBinding"
                                      example  POST /acme/new-account HTTP/1.1
                                               Host: example.com
                                               Content-Type: application/jose+json
                                               {
                                                 "protected": base64url({ "alg": "ES256",
                                                                          "jwk": /* account key */,
                                                                          "nonce": "K60BWPrMQG9SDxBDS_xtSw",
                                                                          "url": "https://example.com/acme/new-account" }),
                                                 "payload": base64url({
                                                     "contact": [ "mailto:cert-admin@example.org",
                                                                  "mailto:admin@example.org" ],
                                                     "termsOfServiceAgreed": true,
                                                     "externalAccountBinding": {
                                                         "protected": base64url({ "alg": "HS256",
                                                                                  "kid": /* keyIdentifier from nonACMEsystem */,
                                                                                  "url": "https://example.com/acme/new-account" }),
                                                         "payload": base64url(/* same as in "jwk" above */),
                                                         "signature": /* MAC using MACkey from nonACMEsystem */ }
                                                 }),
                                                 "signature": "5TWiqIYQfIDfALQv...x9C2mg8JGPxl5bI4"
                                               }

               Server verifies "externalAccountBinding" "protected" "alg"    has supported MAC-based algorithm
                                                                    "kid"    has keyIdentifier provided by nonACMEsystem
                                                                    "nonce"  is not present
                                                                    "url"    = outer JWS
                      retrieves MACkey corresponding to "kid" of "externalAccountBinding"
                      verifies "signature" of "externalAccountBinding" using retrieved MACkey
                               "payload"   of "externalAccountBinding" represents the same key as was used to verify outer "jwk"

    AccountKeyRollover
        Client wants to change PublicKey of AccountReso
                                         to recover from key compromise
                                            mitigate impact of unnoticed key compromise
               request has signatures by oldKey
                                         newKey

        steps  Client creates Inner  represents request by holder of newKey to take over the holder of oldKey
                                     "protected"  "jwk" = PublicKey of newKey pair
                                                  "url" = "url" of Outer
                                                  "nonce" omitted
                                     "payload"    "account" string URL
                                                            = URL of AccountReso being modified
                                                  "oldKey"  JWK
                                     signed by newKey
                              Outer  represents current account holder's assent to this request
                                     "payload" has Inner
                                     signed by oldKey

                      example  POST /acme/key-change HTTP/1.1
                               Host: example.com
                               Content-Type: application/jose+json
                               {
                                 "protected": base64url({ "alg": "ES256",
                                                          "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                          "nonce": "S9XaOcxP5McpnTcWPIhYuB",
                                                          "url": "https://example.com/acme/key-change" }),
                                 "payload": base64url({
                                     "protected": base64url({ "alg": "ES256",
                                                              "jwk": /* new key */,
                                                              "url": "https://example.com/acme/key-change" }),
                                     "payload": base64url({ "account": "https://example.com/acme/acct/evOfKhNU60wg",
                                                            "oldKey": /* old key */ }),
                                     "signature": "Xe8B94RD30Azj2ea...8BmZIRtcSKPSd8gU"
                                 }),
                                 "signature": "5TWiqIYQfIDfALQv...x9C2mg8JGPxl5bI4"
                               }

               Server validates JWS
                      validates POST request belongs to AccountReso
                      checks  Inner is well-formed JWS
                                    has "jwk" not "kid"
                                    verifies using "jwk"
                                    has well-formed "payload"
                                    "url" = Outer "url"
                                    "account" = "kid" in Outer
                                    "oldKey" is the same account key for account in question
                              no Account exists with "jwk" of Inner
                      if AccountReso already exist with newKey
                         then Server may return status code 409 (Conflict)
                                                Location header with URL of that AccountReso
                      if all is right
                         then Server updates AccountReso oldKey with newKey
                                     returns status code 200 (OK)
                         else Server returns error status code
                                             ProblemDocument describing error
                      updating account key may  not change other data of AccountReso
                                           must not invalidate OrdersReso
                                                               AuthorizationReso

    AccountDeactivation
        Client may want when account key is compromised or decommissioned

        example  POST /acme/acct/evOfKhNU60wg HTTP/1.1
                 Host: example.com
                 Content-Type: application/jose+json
                 {
                   "protected": base64url({ "alg": "ES256",
                                            "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                            "nonce": "ntuJWWSic4WVNSqeUmshgg",
                                            "url": "https://example.com/acme/acct/evOfKhNU60wg" }),
                   "payload": base64url({ "status": "deactivated" }),
                   "signature": "earzVLd3m5M4xJzR...bVTqn7R08AKOVf3Y"
                 }

        Server verifies request signed by account key
        if Server accepts request
           then Server updates AccountReso to "deactivated"
                       returns status code 200 (OK)
                               AccountReso
                       cancels AccountReso pending operations such as OrdersReso
                       may delete data related to AccountReso
                           send mail to "contact" of AccountReso
                           not revoke issued Certificates of AccountReso
                       if receives POST or POST-as-GET from "deactivated" AccountReso
                          then return status code 401 (Unauthorized)
                                      error type "urn:ietf:params:acme:error:unauthorized"
                       "deactivated" AccountReso can not request Certificate
                                                         access resources
                                                                OrdersReso or AuthorizationReso
        ACME does not provide a way to reactivate "deactivated" AccountReso

    CertificateIssuance
        steps Client submits order for Certificate to be issued
              Server responds with list of requirements for Client to satisfy before the Certificate is issued
              Client responds by telling Server which ChallengeReso are completed
              Server validates the completed ChallengeReso
              Client submits CSR
              Server issues requested Certificate
                     makes Certificate available to Client

              map  Client                                                   Server
                   [Order]
                   Signature                     ------->
                                                 <-------  Required Authorizations
                   [Responses]
                   Signature                     ------->
                                       <~~~~~~~~Validation~~~~~~~~>
                   [CSR]
                   Signature                     ------->
                                                 <-------          Acknowledgement
                                       <~~~~~~Await issuance~~~~~~>
                   [POST-as-GET request]
                   Signature                     ------->
                                                 <-------              Certificate
                             [] Information covered by request signatures

    ApplyingforCertificateIssuance
        Client POST  to URL of "newOrder"
                     has subset of OrderReso describing Certificate to be issued
                     "identifiers"  array of object
                                    that Client wishes to submit order for
                                    "type"  string
                                            of identifier
                                    "value" string
                                            identifier itself
                                            may = wildcardDomainName  if doing newOrder and
                                                                         "type" = "dns"
                                            if = wildcardDomainName    and
                                               Server accepts newOrder
                                               then Server creates AuthorizationReso with "identifier" value chunk "*." removed
                                                                                          "wildcard" = true
                                            wildcardDomainName = "*." followed by a domain name
                                                               example  "*.example.com"
                                                               described in Subject Alternate Name Extension RFC5280
                     "notBefore"    optional
                                    string
                                    format RFC3339
                                    the notBefore field in Certificate
                                    date on which Certificate becomes valid

                     "notAfter"     optional
                                    string
                                    format RFC3339
                                    the notAfter  field in Certificate
                                    date on which Certificate becomes invalid

                     example  POST /acme/new-order HTTP/1.1
                              Host: example.com
                              Content-Type: application/jose+json
                              {
                                "protected": base64url({ "alg": "ES256",
                                                         "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                         "nonce": "5XJ1L3lEkMG7tR6pA00clA",
                                                         "url": "https://example.com/acme/new-order" }),
                                "payload": base64url({ "identifiers": [
                                                           { "type": "dns", "value": "www.example.org" },
                                                           { "type": "dns", "value": "example.org" } ],
                                                       "notBefore": "2016-01-01T00:04:00+04:00",
                                                       "notAfter": "2016-01-08T00:04:00+04:00" }),
                                "signature": "H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g"
                              }


        Server returns error  if cannot fulfill request
               does not issue Certificate with contents other than those requested
        if Server wants request to be modified
           then Server returns appropiate error type and description

        Server returns status code 201 (Created)
                       OrderReso reflecting Client's request
                                 with "authorizations" Client must complete before Certificate is issued

                       example  HTTP/1.1 201 Created
                                Replay-Nonce: MYAuvOpaoIiywTezizk5vw
                                Link: <https://example.com/acme/directory>;rel="index"
                                Location: https://example.com/acme/order/TOlocE8rfgo
                                {
                                  "status": "pending",
                                  "expires": "2016-01-05T14:09:07.99Z",
                                  "notBefore": "2016-01-01T00:00:00Z",
                                  "notAfter": "2016-01-08T00:00:00Z",
                                  "identifiers": [ { "type": "dns", "value": "www.example.org" },
                                                   { "type": "dns", "value":     "example.org" } ],
                                  "authorizations": [ "https://example.com/acme/authz/PAniVnsZcis",
                                                      "https://example.com/acme/authz/r4HqLzrSrpI" ],
                                  "finalize": "https://example.com/acme/order/TOlocE8rfgo/finalize"
                                }

        for each OrderReso if Client fulfills Server's requirements before "expires"
                              then Server will "finalize" upon request of Client
                                               issue Certificate

        any "pending" AuthorizationReso is a transaction that Client must complete before Server issues Certificate
        if Client fails before "expires"
           then Server may make OrderReso "invalid"
                           delete OrderReso
        assume nothing about the sort order of "identifiers" or "authorizations" of OrderReso

        if Client believes it has fulfilled "authorizations"
           then Client POST to URL of "finalize" of OrderReso
                            "csr"  string
                                   CSR  RFC2986
                                   base64url encoded version of the DER format
                                   does not include headers
                                   is different from PEM

                            example  POST /acme/order/TOlocE8rfgo/finalize HTTP/1.1
                                     Host: example.com
                                     Content-Type: application/jose+json
                                     {
                                       "protected": base64url({ "alg": "ES256",
                                                                "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                                "nonce": "MSF2j2nawWHPxxkE3ZJtKQ",
                                                                "url": "https://example.com/acme/order/TOlocE8rfgo/finalize" }),
                                       "payload": base64url({ "csr": "MIIBPTCBxAIBADBFMQ...FS6aKdZeGsysoCo4H9P", }),
                                       "signature": "uOrUfIIk5RyQ...nw62Ay1cl6AB"
                                     }

        CSR identifiers = newOrder identifiers
        "dns" Identifiers appear in commonName of requested subject name or
                                    extensionRequest RFC2985 that request subjectAltName extension
                                    any sort order
        Specifications defining new identifier types define their locations in signing request of Certificate

        if "finalize" request received and
           if CSR identifiers != OrderReso identifiers          or
              account is not authorized for identifiers in CSR  or
              CA rejects CSR extensions
           then Server returns error
                       may return ProblemDocument with "badCSR"
                                  "detail" with reasons the CSR was rejected
                       leaves OrderReso "ready" to allow new "finalize" request
                                                         amended CSR

        if "finalize" request received and
           OrderReso is not "ready"
           then Server returns status code 403 (Forbidden)
                               ProblemDocument type "orderNotReady"
                Client may POST to URL of OrderReso to read its "status"

        if "finalize" request received and successful
           then Server returns status code 200 (OK)
                               updated OrderReso
                if OrderReso is "invalid"    then Certificate will not be issued
                                                  OrderReso is abandoned
                                "pending"    then Server thinks Client has not fulfilled the requirements
                                                  Client checks "authorizations" for entries still pending
                                "ready"      then Server thinks requirements are fulfilled
                                                         awaits "finalize" request
                                "processing" then Certificate is being issued
                                                  Client POST-as-GET to URL of OrderReso after Retry-After of response
                                "valid"      then issued Certificate is located at "certificate" of response
                                             example  HTTP/1.1 200 OK
                                                      Replay-Nonce: CGf81JWBsq8QyIgPCi9Q9X
                                                      Link: <https://example.com/acme/directory>;rel="index"
                                                      Location: https://example.com/acme/order/TOlocE8rfgo
                                                      {
                                                        "status": "valid",
                                                        "expires": "2016-01-20T14:09:07.99Z",
                                                        "notBefore": "2016-01-01T00:00:00Z",
                                                        "notAfter": "2016-01-08T00:00:00Z",
                                                        "identifiers": [ { "type": "dns", "value": "www.example.org" },
                                                                         { "type": "dns", "value":     "example.org" } ],
                                                        "authorizations": [ "https://example.com/acme/authz/PAniVnsZcis",
                                                                            "https://example.com/acme/authz/r4HqLzrSrpI" ],
                                                        "finalize": "https://example.com/acme/order/TOlocE8rfgo/finalize",
                                                        "certificate": "https://example.com/acme/cert/mAt3xBGaobw"
                                                      }

    PreAuthorization
        some Servers may enable Clients to get authorization for identifier proactively outside ACME
        example  Client hosting virtual servers for collection of names
                        wants authorization before creating virtual servers
                        only creates Certificate when virtual server starts up
        if CA has Server and
           CA has nonACMEsystem authorizing Clients to issue certificates for an identifier
           then CA may provision Server with valid authorizations for OrdersReso of those Clients

        "newAuthz" is not used to issue Certificates with wildcardDomainName

        steps  Server shows URL of "newAuthz" in Directory
               Client POST to URL of "newAuthz"
                           "identifier" object
                                        to appear in resulting AuthorizationReso
                                        "type"  string
                                                of identifier
                                        "value" string
                                                identifier itself

                           example  POST /acme/new-authz HTTP/1.1
                                    Host: example.com
                                    Content-Type: application/jose+json
                                    {
                                      "protected": base64url({ "alg": "ES256",
                                                               "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                               "nonce": "uQpSjlRb4vQVCjVYAyyUWg",
                                                               "url": "https://example.com/acme/new-authz" }),
                                      "payload": base64url({ "identifier": { "type": "dns",
                                                                             "value": "example.org" }}),
                                      "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
                                    }

               Server chosses if Certificates for identifier is issued
                      checks identifier is supported
                             names in blacklist of high-value identifiers
               if Server will not issue for identifier
                  then Server may return status code 403 (Forbidden)
                                         ProblemDocument with reason for rejection
               if Server will issue for identifier
                  then Server builds AuthorizationReso  "identifier" submitted by Client
                                                        "status"     = "pending" unless Server has out-of-band information about Client's authorization status
                                                        "challenges" selected by Server's policy
                              returns status code 201 (Created)
                                      Location header with URL of new AuthorizationReso
                                      AuthorizationReso
                       Client follows authorization process using returned AuthorizationReso

    DownloadingCertificate
        steps  Client POST to ULR of "certificate" of OrderReso
                           example  POST /acme/cert/mAt3xBGaobw HTTP/1.1
                                    Host: example.com
                                    Content-Type: application/jose+json
                                    Accept: application/pem-certificate-chain
                                    {
                                      "protected": base64url({
                                        "alg": "ES256",
                                        "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                        "nonce": "uQpSjlRb4vQVCjVYAyyUWg",
                                        "url": "https://example.com/acme/cert/mAt3xBGaobw"
                                      }),
                                      "payload": "",
                                      "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
                                    }
                      may request other Certificate formats by including Accept header RFC7231
                                  end-entity in DER by including "application/pkix-cert"  RFC2585
                                                                 "application/pkcs7-mime" RFC5751
               Server receives request of Client
                      returns Certificate which is single
                                                   immutable
                                          default format is application/pem-certificate-chain

                              example  HTTP/1.1 200 OK
                                       Content-Type: application/pem-certificate-chain
                                       Link: <https://example.com/acme/directory>;rel="index"
                                       -----BEGIN CERTIFICATE-----
                                       [End-entity certificate contents]
                                       -----END CERTIFICATE-----
                                       -----BEGIN CERTIFICATE-----
                                       [Issuer certificate contents]
                                       -----END CERTIFICATE-----
                                       -----BEGIN CERTIFICATE-----
                                       [Other certificate contents]
                                       -----END CERTIFICATE-----

                      may support other Certificate formats
                          add multiple "Link: rel="up"" header pointing to issuers
                                            for formats that only express one Certificate
                                            so Clients can build TLS1.3 Certificate chain
                              links relation header with "alternate" RFC8288
                                                    to alternative Certificate chain starting with end-entity Certificate
                                                    to express paths to various trust anchors
                                                    then Client decides which "alternate" is optimal
                              headers Cache-Control
                                      Expires  not related to validity period of Certificate
               if Client wants renewed Certificate
                  then Client does new newOrder process

        application/pem-certificate-chain
            contains one or more Certificates
            Certificates use PEM textual encoding RFC7468
                                 strict encoding
                                 have no explanatory text
                                 ABNF "stricttextualmsg" and "eol" are as defined in Section 3
                                      certchain = stricttextualmsg *(eol stricttextualmsg)
            first Certificate is end-entity
            nonFirst Certificates may directly certify the one preceding it
            Certificate validation requires trust anchors be distributed independently
            if peer already possess trust anchor Certificate
               then chain may not have trust anchor Certificate
            "Media Types" registry    Type name: application
                                      Subtype name: pem-certificate-chain
                                      Required parameters: None
                                      Optional parameters: None
                                      Encoding considerations: 7bit
                                      Security considerations: Carries a cryptographic certificate and its associated certificate chain. This media type carries no active content.
                                      Interoperability considerations: None
                                      Published specification: RFC 8555
                                      Applications that use this media type: ACME clients and servers, HTTP servers, other applications that need to be configured with a certificate chain
                                      Additional information:
                                          Deprecated alias names for this type: n/a
                                          Magic number(s): n/a
                                          File extension(s): .pem
                                          Macintosh file type code(s): n/a
                                      Person & email address to contact for further information: See Authors' Addresses section.
                                      Intended usage: COMMON
                                      Restrictions on usage: n/a
                                      Author: See Authors' Addresses section.
                                      Change controller: IETF <iesg@ietf.org>

    CertificateRevocation
        Client POST to URL of "revokeCert"
                    "certificate"  string
                                   Certificate to be revoked
                                   base64url encoded of DER format
                                   different from PEM

                    "reason"  optional
                              int
                              reasonCodes Section 5.3.1 RFC5280
                              used when generating OCSP responses and CRLs
                              if not set
                                 then Server may omit reasonCode CRL entry extension
                                                      when generating OCSP responses and CRLs
                                                 disallow subset of reasonCodes from being used by user
                              if has disallowed reasonCode
                                 then Server rejects request
                                             returns error type "urn:ietf:params:acme:error:badRevocationReason"
                                             ProblemDocument detail may indicate allowed reasonCodes
                    "jwk" in "protected"

                    signed with either AKP
                                       key pair in Certificate

                    example  using AKP                      POST /acme/revoke-cert HTTP/1.1
                                                            Host: example.com
                                                            Content-Type: application/jose+json
                                                            {
                                                              "protected": base64url({
                                                                  "alg": "ES256",
                                                                  "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                                  "nonce": "JHb54aT_KTXBWQOzGYkt9A",
                                                                  "url": "https://example.com/acme/revoke-cert" }),
                                                              "payload": base64url({
                                                                  "certificate": "MIIEDTCCAvegAwIBAgIRAP8...",
                                                                  "reason": 4 }),
                                                              "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
                                                            }

                             using key pair in Certificate  POST /acme/revoke-cert HTTP/1.1
                                                            Host: example.com
                                                            Content-Type: application/jose+json
                                                            {
                                                              "protected": base64url({
                                                                  "alg": "RS256",
                                                                  "jwk": /* certificate's public key */,
                                                                  "nonce": "JHb54aT_KTXBWQOzGYkt9A",
                                                                  "url": "https://example.com/acme/revoke-cert" }),
                                                              "payload": base64url({
                                                                  "certificate": "MIIEDTCCAvegAwIBAgIRAP8...",
                                                                  "reason": 1 }),
                                                              "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
                                                            }

        Server verifies key used to sign request is authorized
                        signature with privateKey corresponds to publicKey in Certificate
                        if account issued Certificate or
                           account holds authorizations for all identifiers in Certificate
                           then account is authorized

               if revocation succeeds
                  then returns status code 200 (OK)
                               example  HTTP/1.1 200 OK
                                        Replay-Nonce: IXVHDyxIRGcTE0VSblhPzw
                                        Content-Length: 0
                                        Link: <https://example.com/acme/directory>;rel="index"
               if revocation fails
                  then returns error
                       example if Certificate is already revoked
                                  then Server returns status code 400 (Bad Request)
                                                      error type "urn:ietf:params:acme:error:alreadyRevoked".
                               HTTP/1.1 403 Forbidden
                               Replay-Nonce: lXfyFzi6238tfPQRwgfmPU
                               Content-Type: application/problem+json
                               Content-Language: en
                               Link: <https://example.com/acme/directory>;rel="index"
                               {
                                 "type": "urn:ietf:params:acme:error:unauthorized",
                                 "detail": "No authorization provided for name example.org"
                               }

    IdentifierAuthorization
        process to authorize account to manage Certificates for identifier
                   check that Client controls privateKey of account
                                              identifier
        one       account  can be associated with different identifiers
        different accounts can be associated with one       identifier
        AuthorizationReso is tied to account key

        steps  Client POST to one URL in "authorizations" of OrderReso
                           example  POST /acme/authz/PAniVnsZcis HTTP/1.1
                                    Host: example.com
                                    Content-Type: application/jose+json
                                    {
                                      "protected": base64url({ "alg": "ES256",
                                                               "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                               "nonce": "uQpSjlRb4vQVCjVYAyyUWg",
                                                               "url": "https://example.com/acme/authz/PAniVnsZcis" }),
                                      "payload": "",
                                      "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
                                    }

               Server returns example  HTTP/1.1 200 OK
                                       Content-Type: application/json
                                       Link: <https://example.com/acme/directory>;rel="index"
                                       {
                                         "status": "pending",
                                         "expires": "2016-01-02T14:09:30Z",
                                         "identifier": { "type": "dns",
                                                         "value": "www.example.org" },
                                         "challenges": [
                                           {
                                             "type": "http-01",
                                             "url": "https://example.com/acme/chall/prV_B7yEyA4",
                                             "token": "DGyRejmCefe7v4NfDGDKfA"
                                           },
                                           {
                                             "type": "dns-01",
                                             "url": "https://example.com/acme/chall/Rg5dV14Gh1Q",
                                             "token": "DGyRejmCefe7v4NfDGDKfA"
                                           }
                                         ]
                                       }
    DeactivatingAuthorization
        Client  wants to relinquish its authorization to issue Certificates for identifier
                POST  to URL of each AuthorizationReso associated with identifier
                      with {"status": "deactivated"}
                      example  POST /acme/authz/PAniVnsZcis HTTP/1.1
                               Host: example.com
                               Content-Type: application/jose+json
                               {
                                 "protected": base64url({
                                   "alg": "ES256",
                                   "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                   "nonce": "xWCM9lGbIyCgue8di6ueWQ",
                                   "url": "https://example.com/acme/authz/PAniVnsZcis"
                                 }),
                                 "payload": base64url({ "status": "deactivated" }),
                                 "signature": "srX9Ji7Le9bjszhu...WTFdtujObzMtZcx4"
                               }

        Server  verifies request is signed by account key that owns AuthorizationReso
                if deactivation is accepted
                   then returns status code 200 (OK)
                                updated AuthorizationReso
                does not treat deactivated AuthorizationReso as sufficient for issuing certificates

    ChallengeResponse
        prove control of identifier
        receive authorization

        Client  wants to respond to "http-01" ChallengeReso
                POST with empty JSON in "payload"
                     to URL of ChallengeReso
                     example  POST /acme/chall/prV_B7yEyA4 HTTP/1.1
                              Host: example.com
                              Content-Type: application/jose+json
                              {
                                "protected": base64url({
                                    "alg": "ES256",
                                    "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                    "nonce": "Q_s3MWoqT05TrdkM2MTDcw",
                                    "url": "https://example.com/acme/chall/prV_B7yEyA4" }),
                                "payload": base64url({}),
                                "signature": "9cbg5JO1Gf5YLjjz...SpkUfcdPai9uVYYQ"
                              }

        Server  updates ChallengeReso of AuthorizationReso using received data
                ignores fields not specified for this type of ChallengeReso
                returns status code 200 (OK)
                        updated ChallengeReso
                if received data is invalid   or
                   can not validate ChallengeReso
                   then Server returns HTTP error
                        Client may undo actions to fulfill ChallengeReso
                                   remove files provisioned to a web server

                updates AuthorizationReso to "valid" or "invalid"
                                          when one ChallengeReso validation is completed
                                          if to "valid" then Server includes "expires"
                may remove completed ChallengeReso
                    modify "expires"
                    not remove "invalid" ChallengeReso

        validation may take time
        Client POST to URL of AuthorizationReso to see when it is finalized
                    example  POST /acme/authz/PAniVnsZcis HTTP/1.1
                             Host: example.com
                             Content-Type: application/jose+json
                             {
                               "protected": base64url({ "alg": "ES256",
                                                        "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                                        "nonce": "uQpSjlRb4vQVCjVYAyyUWg",
                                                        "url": "https://example.com/acme/authz/PAniVnsZcis"}),
                               "payload": "",
                               "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
                             }

        if Client knows when Server validates ChallengeReso
           then Client may not poll until seeing validation request from Server

        if validation is still in progress
           then Server returns status code 200 (OK)
                               may have Retry-After header to give polling interval to Client
                               example  HTTP/1.1 200 OK
                                        Content-Type: application/json
                                        Link: <https://example.com/acme/directory>;rel="index"
                                        {
                                          "status": "valid",
                                          "expires": "2018-09-09T14:09:01.13Z",
                                          "identifier": { "type": "dns",
                                                          "value": "www.example.org" },
                                          "challenges": [ { "type": "http-01",
                                                            "url": "https://example.com/acme/chall/prV_B7yEyA4",
                                                            "status": "valid",
                                                            "validated": "2014-12-01T12:05:13.72Z",
                                                            "token": "IlirfxKKXAsHtmzK29Pj8A" } ]
                                        }

    Challenges
        to complete ChallengeReso  Client has to control identifier
                                                 have privateKey of account

        steps    Server gives "challenges" in AuthorizationReso
                 Client POST to URL in "challenges"

        Server may retry validation if it fails
               sets own retry schedule
               may not retry more than every 5 or 10 seconds
                                       because of propagation delays in HTTP or DNS provisioning
               queries may fail while resource is being set up
                                due to information propagating across cluster
                                       firewall rules not being in place
               ChallengeReso remains "processing" while retrying
                             is marked "invalid" if Server gives up
                             "error" has information about every retry state
                             Retry-After header inclued in response
                                         has time after Server's next retry
        Client can request retry by sending POST to URL of ChallengeReso with new nonce
                                 then Servers may retry immediately
                                                  rate-limit retries to avoid denial-of-service attacks

    HTTPChallenge
        completed over HTTP not HTTPS

        Client will prove it can provision HTTP resources on webServer accessed using DomainName

        "type"  = "http-01"
        "token" string
                random value
                uniquely identifies this challenge
                bits of entropy >= 128
                has no characters outside base64url alphabet
                       base64 padding characters "="
                RFC4086 has additional information on randomness requirements

        example  {
                   "type": "http-01",
                   "url": "https://example.com/acme/chall/prV_B7yEyA4",
                   "status": "pending",
                   "token": "LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0"
                 }

        steps   Client construcs KeyAuthorization from "token" of ChallengeReso
                                                       account key of Client
                       puts KeyAuthorization on webServer Path
                       Path has fixed prefix "/.well-known/acme-challenge/{token}"
                            {token} = "token" of ChallengeReso
                            resource is ASCII representation of KeyAuthorization
                       POST to Server
                            with empty JSON in "payload"
                            signals the ChallengeReso can be validated

                            example  POST /acme/chall/prV_B7yEyA4
                                     Host: example.com
                                     Content-Type: application/jose+json
                                     {
                                       "protected": base64url({
                                         "alg": "ES256",
                                         "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                         "nonce": "UQI1PoRi5OuXzxuX7V7wL0",
                                         "url": "https://example.com/acme/chall/prV_B7yEyA4"
                                       }),
                                       "payload": base64url({}),
                                       "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
                                     }

                Server receives request of Client
                       constructs KeyAuthorization from "token" of ChallengeReso
                                                        account key of Client
                       stores     KeyAuthorization
                       populates URL template "http://{DomainName}/.well-known/acme-challenge/{token}" RFC6570
                       dereferences URL using HTTP GET request
                                              port 80
                                        and may follow redirects
                                        to at least one hosts in DNS A and AAAA records
                                        DomainName may resolve to multiple IPv4 and IPv6
                                        example  GET /.well-known/acme-challenge/LoqXcYV8...jxAjEuX0
                                                 Host: example.org

                webServer receives request of Server
                          may avoid to copy "token" from request to response
                                                    to avoid cross-site scripting vulnerabilities
                          if copies "token" from request to response
                             then webServer first   validates "token" syntax of request
                                            second  copies "token" from request to response
                          returns to Server
                                  example  HTTP/1.1 200 OK
                                           Content-Type: application/octet-stream
                                           LoqXcYV8...jxAjEuX0.9jg46WB3...fm21mqTI

                                           "..." indicates the string is truncated

                Server receives response of webServer
                       may ignore whitespace characters at the end
                       verifies it has well-formed KeyAuthorization
                       verifies KeyAuthorization of Server   equals
                                KeyAuthorization of response
                       updates ChallengeReso to "valid" or "invalid"

                webServer may delete data created for ChallengeReso
                                          after knowing ChallengeReso is "valid" or "invalid"

        "Well-Known URIs" registry    uses template from RFC5785
                                      URI suffix: acme-challenge
                                      Change controller: IETF
                                      Specification document(s): RFC 8555, Section 8.3
                                      Related information: N/A
    DNSChallenge
        Client proves control of DomainName

        "type"   = "dns-01"
        "token"  string
                 random value        RFC4086 has additional information on randomness requirements
                 uniquely identifies this challenge
                 bits of entropy >= 128
                 has no characters outside base64url alphabet
                        padding characters "="
        example  {
                   "type": "dns-01",
                   "url": "https://example.com/acme/chall/Rg5dV14Gh1Q",
                   "status": "pending",
                   "token": "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
                 }

        steps  Client constructs KeyAuthorization from "token"
                                                       account key of Client
                      creates TXT record name  "_acme-challenge" prepended to DomainName
                                         with  Digest = base64url(SHA256(KeyAuthorization))
                      provisions DNS with TXT record
                                 example  if DomainName ="www.example.org"
                                             then Client provision DNS with TXT record _acme-challenge.www.example.org. 300 IN TXT "gfj9Xq...Rg85nM"
                      responds to Server
                               to acknowledge ChallengeReso can be validated
                               with empty JSON in "payload"

                               example  POST /acme/chall/Rg5dV14Gh1Q
                                        Host: example.com
                                        Content-Type: application/jose+json
                                        {
                                          "protected": base64url({
                                            "alg": "ES256",
                                            "kid": "https://example.com/acme/acct/evOfKhNU60wg",
                                            "nonce": "SS2sSl1PtspvFZ08kNtzKd",
                                            "url": "https://example.com/acme/chall/Rg5dV14Gh1Q"
                                          }),
                                          "payload": base64url({}),
                                          "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
                                        }

               Server receives response of Client
                      constructs KeyAuthorization from "token"
                                                       account key of Client
                      stores     KeyAuthorization
                      computes Digest = base64url(SHA256(KeyAuthorization))
                      query TXT records
                      verifies contents of any TXT record match Digest
                      if verification succeed
                         then Server updates ChallengeReso to "valid"
                      if no DNS record is found or
                         DNS record payload do not pass checks
                         then Server updates ChallengeReso to "invalid"

               Client may delete TXT record created for this DNSChallenge
                                            after knowing ChallengeReso is "valid" or "invalid"

    ChangesofTOS
        if Server has new terms of service and
                  wants agreement before accepting new requests
           then Server returns status code 403 (Forbidden)
                               Link header with URL of latest terms-of-service
                                                relation "terms-of-service"
                               error type "urn:ietf:params:acme:error:userActionRequired"
                               "instance" with URL the Client should direct a human to visit
                                                   for instructions on how to agree to the terms
                               example    HTTP/1.1 403 Forbidden
                                          Replay-Nonce: T81bdZroZ2ITWSondpTmAw
                                          Link: <https://example.com/acme/directory>;rel="index"
                                          Link: <https://example.com/acme/terms/2017-6-02>;rel="terms-of-service"
                                          Content-Type: application/problem+json
                                          Content-Language: en
                                          {
                                            "type": "urn:ietf:params:acme:error:userActionRequired",
                                            "detail": "Terms of service have changed",
                                            "instance": "https://example.com/acme/agreement/?token=W8Ih3PswD-8"
                                          }

    Server  that support TLS 1.3 may allow Clients to send 0-RTT
                                 have no restrictions on what data can be carried in 0-RTT
            may use CORS to be accessible from browser Clients W3C.REC-cors-20140116
                         and may set HTTP Access-Control-Allow-Origin = "*"
    Client  may  send HTTP Accept-Language RFC7231
                                           to enable localization of error messages
            must send HTTP User-Agent      RFC7231
                                           may include ACME software name and version
                                                       HTTP software name and version
            JWS  JSON Web Signature RFC7515
                 provides authentication
                 verified by Server before processing
                 uses Flattened JSON Serialization RFC7515
                 has no Unencoded Payload Option RFC7797
                        Unprotected Header RFC7515
                        multiple signatures
                 members  "protected"  "nonce"
                                       "url"  string with URL to which Client directs request
                                              Server checks if equal to URL in HTTP header
                                                               else reject as unauthorized
                                       either "jwk" uses JWK
                                                    has publicKey of privateKey used for "signature"
                                              "kid" Key ID
                                                    string with URL of AccountReso used for "signature"
                                              else Server rejects requests
                                       "alg" = "ES256"  must be supported by Server
                                               "EdDSA"  may  be supported by Server
                                                        using "Ed25519" indicated by "crv" RFC8037
                                             != "none"
                                                MAC  Message Authentication Code algorithm
                                             if unsupported algorithm to Server
                                                then Server returns status code 400 (Bad Request)
                                                                    error type "urn:ietf:params:acme:error:badSignatureAlgorithm"
                                                                    ProblemDocument with "algorithms" with array of supported "alg"
                          "payload"    string
                          "signature"  string with base64url(alg(ASCII(b1 || '.' || b2)))
                                       b1 = base64url(UTF8(content of "protected"))
                                       b2 = base64url(UTF8(content of "payload"  ))
                                       alg()    algorithm defined in "alg"
                                       ASCII()  octets of ASCII representation
                                       || means concatenation
                 if Server supports "alg" and
                           does not support or rejects "jwk"
                    then Server returns status code 400 (Bad Request)
                                        error type "urn:ietf:params:acme:error:badPublicKey"
                                may return ProblemDocument with reason for rejecting the public keys
                                                  examples  "alg" is "RS256" but the modulus "n" is too small
                                                            "alg" is "ES256" but "jwk" does not contain a valid P-256 public key
                                                            "alg" is "EdDSA" and "crv" is "Ed448" but Server only supports "EdDSA" with "Ed25519"
                                                            the corresponding private key is known to have been compromised
                 with HTTP Content-Type = "application/jose+json"
                      else Server returns status code 415 (Unsupported Media Type)

    ES256  RFC7518
           uses P-256
           P-256 has same constants as secp256r1

           P-256        y^2=x^3+a*x+b (mod p)    a = -3
           secp256r1    y^2=x^3+a*x+b (mod p)    a = FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC

           a = -3 (mod p) = FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC

           G  elliptic curve base point
           d  private key
           Q  public  key
              = d*G
           n  order of G
           O  identity element
              = n*G

           SignatureGeneration    m message to sign
                                  e = integer(SHA256(m))
                                  k cryptographically secure random integer
                                    >= 1
                                    <= n-1
                                  (x,y) = k*G
                                  r = integer(x)
                                    size = 32byte
                                  s = (e+r*d)/k (mod n)
                                    size = 32byte
                                  if r = 0 or s = 0  then generate k        again
                                                          calcualte r and s again
                                  output = r || s
                                         size = 64byte
                                  || means concatenation

           SignatureVerification  check  Q  != O
                                         Q*n = O
                                         Q lies on the curve
                                         r > 0
                                         r < n
                                         s > 0
                                         s < n
                                  e = integer(SHA256(m))
                                  u = e/s (mod n)
                                  v = r/s (mod n)
                                  (x,y) = u*G + v*Q
                                  check  (x,y) != O
                                         r = x (mod n)

    KeyAuthorization  = token || '.' || base64url(Thumbprint(accountKey))
                      || means concatenation
                      token       string
                                  uses base64url alphabet

                      Thumbprint  = SHA256(UTF-8 representation of accountKey)
                                  RFC7638

                      accountKey  JWK of Client
                                  only has required members    RFC7518
                                  members ordered lexicographically
                                  for EC  required members are "crv" "kty" "x" "y"
                                          order of members is  "crv" "kty" "x" "y"
                                  for RSA required members are "e" "kty" "n"
                                          order of members is  "e" "kty" "n"
                                  has no whitespace or line breaks before or after any syntactic elements

    JWK  JSON Web Key RFC7517
         content of "x" is base64url encoded
         content of "y" is base64url encoded
         example    {
                        "crv":"P-256",
                        "kty":"EC",
                        "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
                        "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
                    }
    AKP  account key pair
         has privateKey  used by Client to sign   all messages sent
             publicKey   used by Server to verify all messages received
    PKIX  Public Key Infrastructure using X.509 Certificates
          used for authentication of domain names
    CA    certification authorities
          verifies that the Client represents the domain name in Certificate
    CSR   Certificate Signing Request
          PKCS#10
    CORS  Cross-Origin Resource Sharing
    JSON  JavaScript Object Notation
          binary fields in ACME are base64url encoded  Section 5 of RFC4648
                                use the profile specified in JWS in Section 2 of RFC7515
                                trailing '=' characters are stripped    else rejected as improperly encoded

    Certificate  used to validate domain names
                 types   DV "Domain       validation"  may not verify Client's real-world identity
                         OV "Organization validation"  must    verify Client's real-world identity
                         EV "Extended     validation"  must    verify Client's real-world identity

    Errors  reported in HTTP layer with codes 4XX or 5XX
                        ChallengeReso
            "type" within URN namespace "urn:ietf:params:acme:error:"
                   URI  accountDoesNotExist      request specified account that does not exist
                        alreadyRevoked           request specified certificate to be revoked that has already been revoked
                        badCSR                   CSR is unacceptable
                        badNonce                 Client sent unacceptable anti-replay nonce
                        badPublicKey             JWS was signed by unsupported publicKey
                        badRevocationReason      revocation reason provided is not allowed
                        badSignatureAlgorithm    JWS was signed with unsupported algorithm
                        caa                      Certification Authority Authorization (CAA) records forbid the CA from issuing a certificate
                        compound                 Specific error conditions are indicated in the "subproblems" array
                        connection               Server could not connect to validation target
                        dns                      there was a problem with DNS query during identifier validation
                        externalAccountRequired  request must include value for the "externalAccountBinding" field
                        incorrectResponse        Response received didn't match the challenge's requirements
                        invalidContact           contact URL for account was invalid
                        malformed                request message was malformed
                        orderNotReady            request attempted to finalize order that is not ready to be finalized
                        rateLimited              request exceeds rate limit
                        rejectedIdentifier       Server will not issue certificates for the identifier
                        serverInternal           Server experienced an internal error
                        tls                      Server received TLS error during validation
                        unauthorized             Client lacks sufficient authorization
                        unsupportedContact       contact URL for account used an unsupported protocol scheme
                        unsupportedIdentifier    identifier is of unsupported type
                        userActionRequired       Visit "instance" URL and take actions specified there

                   example  error type "badCSR"  refers to  "type":"urn:ietf:params:acme:error:badCSR"
                   Servers  may use other URI
                            do not use ACME URN namespace for errors not listed in the appropriate IANA registry
                   Clients  may display "detail" field of all errors
            may come with ProblemDocument
            ProblemDocument  RFC7807
                             provides additional information
                             "subproblems"  may be included
                                            need not all have same type
                                            do not need to match top level type
                                            has multiple errors in response to request
                                                JSON array of ProblemDocument
                                                each ProblemDocument with "identifier"
                             "identifier" can only be inside ProblemDocument of "subproblems"
                                          used by Clients
                                          hints that an operation would succeed if that identifier were omitted
                                          example  if newOrder contains ten DNS "identifier" and
                                                      Server returns ProblemDocument with two "subproblems" referencing two "identifier"
                                                      then Client may do newOrder containing only eight "identifier"
                                                   HTTP/1.1 403 Forbidden
                                                   Content-Type: application/problem+json
                                                   Link: <https://example.com/acme/directory>;rel="index"
                                                   {
                                                       "type": "urn:ietf:params:acme:error:malformed",
                                                       "detail": "Some of the identifiers requested were rejected",
                                                       "subproblems": [
                                                           {
                                                               "type": "urn:ietf:params:acme:error:malformed",
                                                               "detail": "Invalid underscore in DNS name \"_example.org\"",
                                                               "identifier": {
                                                                   "type": "dns",
                                                                   "value": "_example.org"
                                                               }
                                                           },
                                                           {
                                                               "type": "urn:ietf:params:acme:error:rejectedIdentifier",
                                                               "detail": "This CA will not issue for \"example.net\"",
                                                               "identifier": {
                                                                   "type": "dns",
                                                                   "value": "example.net"
                                                               }
                                                           }
                                                       ]
                                                   }

    base64url  Base64 Encoding with URL and Filename Safe Alphabet
                ________________________________________________________________
               | Value Encoding  Value Encoding  Value Encoding  Value Encoding |
               |     0 A            17 R            34 i            51 z        |
               |     1 B            18 S            35 j            52 0        |
               |     2 C            19 T            36 k            53 1        |
               |     3 D            20 U            37 l            54 2        |
               |     4 E            21 V            38 m            55 3        |
               |     5 F            22 W            39 n            56 4        |
               |     6 G            23 X            40 o            57 5        |
               |     7 H            24 Y            41 p            58 6        |
               |     8 I            25 Z            42 q            59 7        |
               |     9 J            26 a            43 r            60 8        |
               |    10 K            27 b            44 s            61 9        |
               |    11 L            28 c            45 t            62 -        |
               |    12 M            29 d            46 u            63 _        |
               |    13 N            30 e            47 v                        |
               |    14 O            31 f            48 w           pad =        |
               |    15 P            32 g            49 x                        |
               |    16 Q            33 h            50 y                        |
               |________________________________________________________________|

               ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_
               padding is ommited for ACME

CSR  Entity  defines signature algorithm
             generates pair publicKey
                            privateKey
                            that depends on signature algorithm
             constructs CertificationRequest with publicKey
             requests certificate to CA using CertificationRequest

     ASN.1 from RFC5912
     CertificationRequest ::= SEQUENCE {
        certificationRequestInfo  SEQUENCE {
            version                   INTEGER,
            subject                   Name,
            subjectPublicKeyInfo      SEQUENCE {
                algorithm                 AlgorithmIdentifier{PUBLIC-KEY, {PublicKeyAlgorithms}},
                subjectPublicKey          BIT STRING
            },
            attributes                [0] IMPLICIT SET OF AttributeSet{{AttributeList}}
         },
         signatureAlgorithm        AlgorithmIdentifier {SIGNATURE-ALGORITHM, {SignatureAlgorithms}},
         signature                 BIT STRING
     }
     version  INTEGER Value = 0
              for compatibility with future revisions

     subject  Name ::= CHOICE { -- only one possibility for now -- rdnSequence  RDNSequence }
              RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
              DistinguishedName ::=   RDNSequence
              RelativeDistinguishedName  ::= SET SIZE (1 .. MAX) OF SingleAttribute { {SupportedAttributes} }
              SingleAttribute{ATTRIBUTE:AttrSet} ::= SEQUENCE {
                  type      ATTRIBUTE.&id({AttrSet}),
                  value     ATTRIBUTE.&Type({AttrSet}{@type})
              }
              SupportedAttributes ATTRIBUTE ::= {
                  at-name | at-surname | at-givenName | at-initials | at-generationQualifier | at-x520CommonName |
                  at-x520LocalityName | at-x520StateOrProvinceName | at-x520OrganizationName | at-x520OrganizationalUnitName |
                  at-x520Title | at-x520dnQualifier | at-x520countryName | at-x520SerialNumber | at-x520Pseudonym |
                  at-domainComponent | at-emailAddress, ... }
              ATTRIBUTE ::= CLASS {
                  &id             OBJECT IDENTIFIER UNIQUE,
                  &Type           OPTIONAL,
                  &equality-match MATCHING-RULE OPTIONAL,
                  &minCount       INTEGER DEFAULT 1,
                  &maxCount       INTEGER OPTIONAL
              } WITH SYNTAX {
                  [TYPE &Type]
                  [EQUALITY MATCHING RULE &equality-match]
                  [COUNTS [MIN &minCount] [MAX &maxCount]]
                  IDENTIFIED BY &id
              }
              distinguished name of Entity
                                 defined in X.501
                                 attributes  defined in RFC2985
                                                        X.520
                                             commonName              domain name to certify
                                                                     example  *.example.com
                                             organizationName        business name
                                                                     example  Exomple Fondoton, Inc.
                                             organizationalUnitName  Department Name
                                                                     example  Finance
                                             localityName            town  city
                                                                     example  Edinburgh
                                             stateOrProvinceName     region  county
                                                                     example  Normandy
                                             countryName             two-letter code of country
                                                                     ISO 3166-1 alpha-2
                                                                     example  US
                                             emailAddress            example  admin@example.com

     algorithm  has information about publicKey of Entity
                this only shows data for secp256r1 use case
                AlgorithmIdentifier{PUBLIC-KEY, {PublicKeyAlgorithms}}
                AlgorithmIdentifier{ALGORITHM-TYPE, ALGORITHM-TYPE:AlgorithmSet} ::= SEQUENCE {
                    algorithm   ALGORITHM-TYPE.&id({AlgorithmSet}),
                    parameters  ALGORITHM-TYPE.&Params({AlgorithmSet}{@algorithm}) OPTIONAL
                }
                PublicKeyAlgorithms PUBLIC-KEY ::= { PKIXAlgs-2009.PublicKeys, ..., PKIX1-PSS-OAEP-Algorithms-2009.PublicKeys}
                PublicKeys PUBLIC-KEY ::= { pk-rsa  | pk-dsa  | pk-dh   | pk-kea, ..., pk-ec   | pk-ecDH | pk-ecMQV }
                pk-ec PUBLIC-KEY ::= {
                    IDENTIFIER id-ecPublicKey
                    KEY ECPoint
                    PARAMS TYPE ECParameters ARE required
                    -- Private key format not in this module --
                    CERT-KEY-USAGE { digitalSignature, nonRepudiation, keyAgreement, keyCertSign, cRLSign }
                }
                PUBLIC-KEY ::= CLASS {
                    &id             OBJECT IDENTIFIER UNIQUE,
                    &KeyValue       OPTIONAL,
                    &Params         OPTIONAL,
                    ¶mPresence  ParamOptions DEFAULT absent,
                    &keyUsage       KeyUsage OPTIONAL,
                    &PrivateKey     OPTIONAL
                } WITH SYNTAX {
                    IDENTIFIER &id
                    [KEY &KeyValue]
                    [PARAMS [TYPE &Params] ARE ¶mPresence]
                    [CERT-KEY-USAGE &keyUsage]
                    [PRIVATE-KEY &PrivateKey]
                }
                id-ecPublicKey OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
                ECParameters ::= CHOICE { namedCurve CURVE.&id({NamedCurve}) }
                CURVE ::= CLASS { &id OBJECT IDENTIFIER UNIQUE } WITH SYNTAX { ID &id }
                NamedCurve CURVE ::= {
                    { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } | { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } |
                    { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } | { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } |
                    { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 }, ... -- Extensible
                }
                secp256r1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 }

     subjectPublicKey  this only shows data for secp256r1 use case
                       implementations must support uncompressed form of ECC publicKey
                                       may  support   compressed form of ECC publicKey
                                       must not support   hybrid form of ECC publicKey
                       pk-ec has   ECPoint ::= OCTET STRING
                       if publicKey is   compressed then ECPoint Value = follow Sections 2.3.3 of SEC1
                       if publicKey is uncompressed then ECPoint Value = 0x04 || x || y
                                                                         size = 1+32+32 bytes
                                                                         (x,y) of publicKey
                       BIT STRING Value = 0x00 || bitS
                                          first byte indicates how many bits in last byte of bitS are ignored
                                          bitS = converted ECPoint Value
                                                 most  significant bit of ECPoint Value is the
                                                 most  significant bit of bitS          and so on
                                                 least significant bit of ECPoint Value is the
                                                 least significant bit of bitS          and so on
                                          section 8.6 of X.690

     attributes  [0] IMPLICIT SET OF AttributeSet{{AttributeList}}    go to 8.14.4 of X.690 to understand this ASN.1
                 AttributeSet{ATTRIBUTE:AttrSet} ::= SEQUENCE {
                     type      ATTRIBUTE.&id({AttrSet}),
                     values    SET SIZE (1..MAX) OF ATTRIBUTE. &Type({AttrSet}{@type})
                 }
                 AttributeList ATTRIBUTE ::= {at-extension-req, ...}
                 at-extension-req ATTRIBUTE ::= { TYPE ExtensionReq IDENTIFIED BY id-ExtensionReq }
                 id-ExtensionReq OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 14}
                 ExtensionReq ::= SEQUENCE SIZE (1..MAX) OF Extension{{CertExtensions}}
                 Extension{EXTENSION:ExtensionSet} ::= SEQUENCE {
                    extnID      EXTENSION.&id({ExtensionSet}),
                    critical    BOOLEAN -- (EXTENSION.&Critical({ExtensionSet}{@extnID}))
                                  DEFAULT FALSE,
                    extnValue   OCTET STRING (CONTAINING EXTENSION.&ExtnType({ExtensionSet}{@extnID}))
                                  -- contains the DER encoding of the ASN.1 value corresponding to the extension type identified by extnID
                }
                CertExtensions EXTENSION ::= {
                    ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | ext-KeyUsage | ext-PrivateKeyUsagePeriod |
                    ext-CertificatePolicies | ext-PolicyMappings | ext-SubjectAltName | ext-IssuerAltName |
                    ext-SubjectDirectoryAttributes | ext-BasicConstraints | ext-NameConstraints | ext-PolicyConstraints |
                    ext-ExtKeyUsage | ext-CRLDistributionPoints | ext-InhibitAnyPolicy | ext-FreshestCRL |
                    ext-AuthorityInfoAccess | ext-SubjectInfoAccessSyntax, ... }
                may have challengePassword  RFC2985
                         extensionRequest   RFC2985

     signatureAlgorithm  this only shows data for secp256r1 use case
                         AlgorithmIdentifier {SIGNATURE-ALGORITHM, {SignatureAlgorithms}}
                         SIGNATURE-ALGORITHM ::= CLASS {
                             &id             OBJECT IDENTIFIER UNIQUE,
                             &Value          OPTIONAL,
                             &Params         OPTIONAL,
                             ¶mPresence  ParamOptions DEFAULT absent,
                             &HashSet        DIGEST-ALGORITHM OPTIONAL,
                             &PublicKeySet   PUBLIC-KEY OPTIONAL,
                             &smimeCaps      SMIME-CAPS OPTIONAL
                         } WITH SYNTAX {
                             IDENTIFIER &id
                             [VALUE &Value]
                             [PARAMS [TYPE &Params] ARE ¶mPresence ]
                             [HASHES &HashSet]
                             [PUBLIC-KEYS &PublicKeySet]
                             [SMIME-CAPS &smimeCaps]
                         }
                         SignatureAlgorithms SIGNATURE-ALGORITHM ::= {
                            PKIXAlgs-2009.SignatureAlgs, ...,
                            PKIX1-PSS-OAEP-Algorithms-2009.SignatureAlgs }
                         SignatureAlgs SIGNATURE-ALGORITHM ::= {
                             sa-rsaWithMD2      | sa-rsaWithMD5      |
                             sa-rsaWithSHA1     | sa-dsaWithSHA1     |
                             sa-ecdsaWithSHA1, ..., -- Extensible
                             sa-dsaWithSHA224   | sa-dsaWithSHA256   |
                             sa-ecdsaWithSHA224 | sa-ecdsaWithSHA256 |
                             sa-ecdsaWithSHA384 | sa-ecdsaWithSHA512
                         }
                         sa-ecdsaWithSHA256 SIGNATURE-ALGORITHM ::= {
                             IDENTIFIER ecdsa-with-SHA256
                             VALUE ECDSA-Sig-Value
                             PARAMS TYPE NULL ARE absent
                             HASHES { mda-sha256 }
                             PUBLIC-KEYS { pk-ec }
                             SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA256 }
                         }
                         ecdsa-with-SHA256 OBJECT IDENTIFIER ::= {
                             iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }

     signature  this only shows data for secp256r1 use case
                steps  generate r and s of SignatureGeneration of ES256
                                                               with key pair of Entity
                                                               with m = DER encoded certificationRequestInfo
                       if  r  left most significant byte = 0 then remove it and repeat this step until not true
                       if  s  left most significant byte = 0 then remove it and repeat this step until not true
                       if  r  left most significant bit  = 1 then append one byte to the left with value 0
                       if  s  left most significant bit  = 1 then append one byte to the left with value 0
                       put r  in Value of INTEGER r of ECDSA-Sig-Value
                       put s  in Value of INTEGER s of ECDSA-Sig-Value

                ECDSA-Sig-Value ::= SEQUENCE { r  INTEGER, s  INTEGER }

                BIT STRING Value = 0x00 || ECDSA-Sig-Value
                                   first byte indicates how many bits in last byte of ECDSA-Sig-Value are ignored

     example  using hexadecimal representation
                    secp256r1

              data starts with        ---------->               30 82 01 80 30...

              CertificationRequest      TagType  SEQUENCE            = 30
                                        Length in next 2 bytes       = 82
                                        Length                       = 01 80
              CertificationRequestInfo  TagType  SEQUENCE            = 30
                                        Length in next 2 bytes       = 82
                                        Length                       = 01 25
              version                   TagType  INTEGER             = 02
                                        Length                       = 01
                                        Value                        = 00
              subject                   TagType  SEQUENCE            = 30
                                        Length in next 1 bytes       = 81
                                        Length                       = 87
                     ____               TagType  SET                 = 31
                                        Length                       = 0B
                                        TagType  SEQUENCE            = 30
                                        Length                       = 09
                                        TagType  OBJECT              = 06
                                        Length                       = 03
                                        Value    Country             = 55 04 06
                                        TagType  PRINTABLESTRING     = 13
                                        Length                       = 02
                                        Value    US                  = 55 53
                     ____               TagType  SET                 = 31
                                        Length                       = 13
                                        TagType  SEQUENCE            = 30
                                        Length                       = 11
                                        TagType  OBJECT              = 06
                                        Length                       = 03
                                        Value    State               = 55 04 08
                                        TagType  UTF8STRING          = 0C
                                        Length                       = 0A
                                        Value    California          = 43 61 6C 69 66 6F 72 6E 69 61
                     ____               TagType  SET                 = 31
                                        Length                       = 11
                                        TagType  SEQUENCE            = 30
                                        Length                       = 0F
                                        TagType  OBJECT              = 06
                                        Length                       = 03
                                        Value    Locality            = 55 04 07
                                        TagType  UTF8STRING          = 0C
                                        Length                       = 08
                                        Value                        = 4E 65 77 20 59 6F 72 6B
                     ____               TagType  SET                 = 31
                                        Length                       = 16
                                        TagType  SEQUENCE            = 30
                                        Length                       = 14
                                        TagType  OBJECT              = 06
                                        Length                       = 03
                                        Value    Organization        = 55 04 0A
                                        TagType  UTF8STRING          = 0C
                                        Length                       = 0D
                                        Value                        = 4D 75 6E 73 74 65 72 73 20 2E 69 6E 63
                     ____               TagType  SET                 = 31
                                        Length                       = 16
                                        TagType  SEQUENCE            = 30
                                        Length                       = 14
                                        TagType  OBJECT              = 06
                                        Length                       = 03
                                        Value    Common Name         = 55 04 03
                                        TagType  UTF8STRING          = 0C
                                        Length                       = 0D
                                        Value                        = 2A 2E 65 78 61 6D 70 6C 65 2E 63 6F 6D
                     ____               TagType  SET                 = 31
                                        Length                       = 20
                                        TagType  SEQUENCE            = 30
                                        Length                       = 1E
                                        TagType  OBJECT              = 06
                                        Length                       = 09
                                        Value    email address       = 2A 86 48 86 F7 0D 01 09 01
                                        TagType  IA5STRING           = 16
                                        Length                       = 11
                                        Value                        = 61 64 6D 69 6E 40 65 78 61 6D 70 6C 65 2E 63 6F 6D
              SubjectPublicKeyInfo      TagType  SEQUENCE            = 30
                                        Length                       = 59
              AlgorithmIdentifier       TagType  SEQUENCE            = 30
                                        Length                       = 13
              ALGORITHM.&id             TagType  OBJECT              = 06
                                        Length                       = 07
                                        Value    id-ecPublicKey      = 2A 86 48 CE 3D 02 01
              ALGORITHM.&Type           TagType  OBJECT              = 06
                                        Length                       = 08
                                        Value    secp256r1           = 2A 86 48 CE 3D 03 01 07
              subjectPublicKey          TagType  BIT STRING          = 03
                                        Length                       = 42
                                        Value                        = 00 04 CE FE 2F 9A D8 78 A3 3B F4 65 C2 D0 DF 01 DB 6D 1C A4 41 F9 10 F3 51 46 82 79 CA 8D 52 35 50 B1 90 CE 06 07 38 35 F9 FA 91 52 31 83 2B 17 C1 D7 AC DE 1B BE 01 35 55 10 0F 65 86 97 45 4B FB 23
              attributes                TagType  cont [ 0 ]          = A0
                                        Length                       = 3B
              Attribute                 TagType  SEQUENCE            = 30
                                        Length                       = 1A
                                        TagType  OBJECT              = 06
                                        Length                       = 09
                                        Value    unstructuredName    = 2A 86 48 86 F7 0D 01 09 02
                                        TagType  SET                 = 31
                                        Length                       = 0D
                                        TagType  UTF8STRING          = 0C
                                        Length                       = 0B
                                        Value                        = 47 75 75 67 6C 65 20 2E 69 6E 63
              Attribute                 TagType  SEQUENCE            = 30
                                        Length                       = 1D
                                        TagType  OBJECT              = 06
                                        Length                       = 09
                                        Value    challengePassword   = 2A 86 48 86 F7 0D 01 09 07
                                        TagType  SET                 = 31
                                        Length                       = 10
                                        TagType  UTF8STRING          = 0C
                                        Length                       = 0E
                                        Value                        = 63 68 6F 68 6F 68 6F 68 6F 68 6F 66 6F 69
              signatureAlgorithm        TagType  SEQUENCE            = 30
                                        Length                       = 0A
                                        TagType  OBJECT              = 06
                                        Length                       = 08
                                        Value    ecdsa-with-SHA256   = 2A 86 48 CE 3D 04 03 02
              signature                 TagType  BIT STRING          = 03
                                        Length                       = 49
                                        Value                        = 00
                                                                     = 30 46
                                                                     = 02 21
                                                                     = 00 D4 7D 86 A0 05 67 27 52 6E 36 86 A7 BC 68 1B 6C 01 CE CD B7 F6 E7 7F A4 89 44 67 27 1F 6B 24 29
                                                                     = 02 21
                                                                     = 00 F4 FA C4 DE F7 32 14 2C 56 0A E5 EF A9 E5 BD 69 87 FC 95 03 85 33 A7 E1 74 D7 69 05 17 1E 41 15

X.509  RFC5280
       Certificate ::= SEQUENCE {
               tbsCertificate       TBSCertificate,
               signatureAlgorithm   AlgorithmIdentifier,
               signatureValue       BIT STRING
       }
       TBSCertificate ::= SEQUENCE {
            version         [0]  EXPLICIT Version DEFAULT v1,
            serialNumber         CertificateSerialNumber,
            signature            AlgorithmIdentifier,
            issuer               Name,
            validity             Validity,
            subject              Name,
            subjectPublicKeyInfo SubjectPublicKeyInfo,
            issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version MUST be v2 or v3
            subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version MUST be v2 or v3
            extensions      [3]  EXPLICIT Extensions OPTIONAL        -- If present, version MUST be v3
       }
       Version ::= INTEGER { v1(0), v2(1), v3(2) }
       CertificateSerialNumber ::= INTEGER
       Validity ::= SEQUENCE {
            notBefore      Time,
            notAfter       Time
       }
       Time ::= CHOICE {
            utcTime        UTCTime,
            generalTime    GeneralizedTime
       }
       UniqueIdentifier ::= BIT STRING
       SubjectPublicKeyInfo ::= SEQUENCE {
            algorithm            AlgorithmIdentifier,
            subjectPublicKey     BIT STRING
       }
       Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
       Extension  ::= SEQUENCE {
            extnID      OBJECT IDENTIFIER,
            critical    BOOLEAN DEFAULT FALSE,
            extnValue   OCTET STRING -- contains the DER encoding of an ASN.1 value corresponding to the extension type identified by extnID
       }
       GeneralizedTime  YYYYMMDDHHMMSSZ
                        seconds never ommited
                        used if year >= 2050
       UTCTime          YYMMDDHHMMSSZ
                        seconds never ommited
                        used if year <  2050
                        example  2018-10-05 01:38:17 GMT = 181005013817Z = 31 38 31 30 30 35 30 31 33 38 31 37 5a = Value of UTCTime
                                 2019-10-05 01:38:17 GMT = 191005013817Z = 31 39 31 30 30 35 30 31 33 38 31 37 5a = Value of UTCTime

NormalvsCompact  Normal   The Netscape/Microsoft browser wars in the mid-90's were really vicious and competitive. They really
                          had it out for each other. Netscape had developed the SSL protocol. The initial version had cryptographic
                          flaws and was broken pretty quickly, and never released. The first production version was SSL 2, which was
                          in use for a few years. (I don't know the exact versions of Navigator it shipped in.)

                          SSL 2 had some flaws, both cryptographic and practical; not dramatic enough to make replacing it a crisis,
                          but it clearly needed some work from early on.

                          As a part of the cutthroat competition, Microsoft decided to revise the SSL 2 protocol with some additions
                          of their own, and specified a protocol called "PCT" that was derived from SSL 2. It was only supported in
                          IE and IIS.

                          Netscape also wanted to address SSL 2 issues, but wasn't going to let Microsoft take leadership/ownership
                          in the standard, so they developed SSL 3.0, which was a more significant departure.

                          Various people in the industry & community didn't want a fork, so we (Consensus Development, where I worked
                          with Christopher Allen at the time, and where I had written the SSL 3.0 reference implementation under
                          contract to Netscape) hosted a meeting between representatives from Netscape and Microsoft; I forget
                          everyone who was there, but I recall that Bruce Schneier was there (before he was famous), and probably
                          Paul Kocher, who had designed the SSL 3 protocol; Barbara Fox represented Microsoft. And we negotiated a
                          deal where Microsoft and Netscape would both support the IETF taking over the protocol and standardizing it
                          in an open process, which led to me editing the RFC.

                          As a part of the horsetrading, we had to make some changes to SSL 3.0 (so it wouldn't look the IETF was
                          just rubberstamping Netscape's protocol), and we had to rename the protocol (for the same reason). And thus
                          was born TLS 1.0 (which was really SSL 3.1). And of course, now, in retrospect, the whole thing looks silly.

                          http://tim.dierks.org/2014/05/security-standards-and-name-changes-in.html

                 Compact  protocols  SSL developed by Netscape
                                         version 1    initial version
                                                      never released
                                                      had cryptographic flaws
                                                 2    first production version
                                                      few years of use
                                                      needed work early
                                                      flaws   cryptographic
                                                              practical
                                                              addresed by Netscape
                                                                          Microsoft
                                                      replacing was not a crisis
                                                      used by unknow version of Navigator
                                                      revised and has additions by Microsoft
                                                 3.0  created to fix SSL 2 issues
                                                                 not let Microsoft take leadership/ownership in the standard
                                                      more significant departure from standard
                                                      fork not wanted by people in industry
                                                                                   community
                                                      designed by Paul Kocher
                                                      reference implementation written by Tim Dierks
                                                 3.1  renamed to TLS 1.0
                                                      born because of TheMeeting
                                     PCT specified by microsoft
                                         derived from SSL 2
                                         made to compete with SSL 2
                                         only supported by IE
                                                           IIS
                          War     who takes leadership/ownership in the standard
                                  opponents   Netscape
                                              Microsoft
                                  mid-90's
                                  really  vicious
                                          competitive cutthroat
                                          had each other out
                                  TheMeeting  hosted by ConsensusDevelopment  where SSL version 3.0 reference implementation was written
                                                                              relevant workers  Tim Dierks
                                                                                                Christopher Allen
                                              attendees  Netscape   Tim Dierks
                                                                    Bruce Schneier
                                                                    probably Paul Kocher
                                                         Microsoft  Barbara Fox
                                                         more forgotten people
                                              NegotiatedDeal  IETF takes over SSL
                                                                   standardizes SSL
                                                              make changes to SSL version 3.0
                                                              rename SSL version 3.0 to TLS 1.0
                                                              hide IETF rubberstamping on SSL
                                                              Tim Dierks edits RFC

next update changes  character font           into    Gabor Patch font
                     left to right reading    into    one on top of the other font zooming
            adds program that transforms text from Normal  to Compact
                                                   Compact to Normal