github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/zcrypto_schemas/zcrypto.py (about)

     1  from zschema.leaves import *
     2  from zschema.compounds import *
     3  import zschema.registry
     4  
     5  # Schema for JSON output of those zcrypto exports used by zgrab2 / ztag.
     6  
     7  # Mostly copied from zmap/zgrab/zgrab_schema.py, then merged in more
     8  # recent changes from ztag, then converted sub_records into
     9  # SubRecordTypes.
    10  
    11  # Helper function for types where unknown values have a special value.
    12  # known are the known values, range generates the keys, and unknown is
    13  # either a static value or a function mapping unknown keys to values.
    14  def getUnknowns(known, range, unknown="unknown"):
    15      if not callable(unknown):
    16          staticValue = unknown
    17          unknown = lambda x: staticValue
    18      ret = {i: unknown(i) for i in range}
    19      ret.update(known)
    20      return ret
    21  
    22  
    23  
    24  # x509/pkix/pkix.go: Name (pkix/json.go - auxName)
    25  DistinguishedName = SubRecordType({
    26      "serial_number": ListOf(String(), doc="serialNumber elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.5)"),
    27      "common_name": ListOf(WhitespaceAnalyzedString(), doc="commonName (CN) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.3)"),
    28      "surname": ListOf(WhitespaceAnalyzedString(), doc="surname (SN) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.4)"),
    29      "country": ListOf(WhitespaceAnalyzedString(), doc="countryName (C) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.6)"),
    30      "locality": ListOf(WhitespaceAnalyzedString(), doc="localityName (L) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.7)"),
    31      "province": ListOf(WhitespaceAnalyzedString(), doc="stateOrProviceName (ST) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.8)"),
    32      "street_address": ListOf(WhitespaceAnalyzedString(), doc="streetAddress (STREET) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.9)"),
    33      "organization": ListOf(WhitespaceAnalyzedString(), doc="organizationName (O) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.10)"),
    34      "organizational_unit": ListOf(WhitespaceAnalyzedString(), doc="organizationalUnit (OU) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.11)"),
    35      "postal_code": ListOf(String(), doc="postalCode elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.17)"),
    36      "domain_component": ListOf(WhitespaceAnalyzedString(), doc="domainComponent (DC) elements of the distinguished name (OBJECT IDENTIFIER 0.9.2342.19200300.100.1.25)"),
    37      "email_address": ListOf(WhitespaceAnalyzedString(), doc="emailAddress (E) elements of the distinguished name (OBJECT IDENTIFIER 1.2.840.113549.1.9.1)"),
    38      "given_name": ListOf(WhitespaceAnalyzedString(), doc="givenName (G) elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.42)"),
    39      "jurisdiction_country":ListOf(WhitespaceAnalyzedString(), doc="jurisdictionCountry elements of the distinguished name (OBJECT IDENTIFIER 1.3.6.1.4.1.311.60.2.1.3)"),
    40      "jurisdiction_locality":ListOf(WhitespaceAnalyzedString(), doc="jurisdictionLocality elements of the distinguished name (OBJECT IDENTIFIER 1.3.6.1.4.1.311.60.2.1.1)"),
    41      "jurisdiction_province":ListOf(WhitespaceAnalyzedString(), doc="jurisdictionStateOrProvice elements of the distinguished name (OBJECT IDENTIFIER 1.3.6.1.4.1.311.60.2.1.2)"),
    42      "organization_id": ListOf(WhitespaceAnalyzedString(), doc="organizationId elements of the distinguished name (OBJECT IDENTIFIER 2.5.4.97)"),
    43  })
    44  
    45  # x509/pkix/pkix.go: Extension (via auxExtension in x509/json.go)
    46  UnknownExtension = SubRecordType({
    47      # both id and value are omitempty
    48      "id": OID(doc="The OBJECT IDENTIFIER identifying the extension."),
    49      "critical": Boolean(doc="Certificates should be rejected if they have critical extensions the validator does not recognize."),
    50      "value": IndexedBinary(doc="The raw value of the extnValue OCTET STREAM."),
    51  }, doc="An unparsed X.509 extension value.")
    52  
    53  # x509/pkix/pkix.go: type EDIPartyName struct
    54  EDIPartyName = SubRecordType({
    55      "name_assigner": WhitespaceAnalyzedString(doc="The nameAssigner (a DirectoryString)", required=False),
    56      "party_name": WhitespaceAnalyzedString(doc="The partyName (a DirectoryString)"),
    57  }, doc="An X.400 generalName representing an Electronic Data Interchange (EDI) entity.")
    58  
    59  # x509/pkix/json.go: auxOtherName / OtherName
    60  OtherName = SubRecordType({
    61      "id": OID(doc="The OBJECT IDENTIFIER identifying the syntax of the otherName value."),
    62      "value": IndexedBinary(doc="The raw otherName value."),
    63  })
    64  
    65  CABFOrganizationID = SubRecordType({
    66      "scheme": WhitespaceAnalyzedString(),
    67      "country": WhitespaceAnalyzedString(),
    68      "state": WhitespaceAnalyzedString(),
    69      "reference": WhitespaceAnalyzedString(),
    70  })
    71  
    72  QCTypes = SubRecordType({
    73      "ids": ListOf(OID(doc="Included QC type OIDs")),
    74  })
    75  
    76  MonetaryLimit = SubRecordType({
    77      "currency": String(doc="Currency, if provided as a string"),
    78      "currency_number": Signed64BitInteger(doc="Currency, if provided as an integer"),
    79      "amount": Signed64BitInteger(doc="Value in currency"),
    80      "exponent": Signed64BitInteger(doc="Total is amount times 10 raised to the exponent"),
    81  }, doc="Value limit for a financial transaction")
    82  
    83  PDSLocation = SubRecordType({
    84      "url": URL(doc="Location of the PDS"),
    85      "language": String(doc="Locale code"),
    86  }, doc="PDS Location entry")
    87  
    88  PDSLocations = SubRecordType({
    89      "locations": ListOf(PDSLocation(), doc="Included PDS locations"),
    90  })
    91  
    92  QCLegislation = SubRecordType({
    93      "country_codes": ListOf(String(doc="Country codes for the set of countries where this certificate issued as a qualified certificate"))
    94  }, doc="List of countries where this certificate is qualified")
    95  
    96  QCStatementsExtensions = SubRecordType({
    97      "ids": ListOf(OID(doc="All included statement OIDs")),
    98      "parsed": SubRecord({
    99          "etsi_compliance": ListOf(Boolean(doc="True if present (Statement ID 0.4.0.1862.1.1)")),
   100          "sscd": ListOf(Boolean(doc="True if present (Statement ID 0.4.0.1862.1.4")),
   101          "types": ListOf(QCTypes(), doc="Statement ID 0.4.0.1862.1.6"),
   102          "limit": ListOf(MonetaryLimit(), doc="Statement ID 0.4.0.1862.1.2"),
   103          "pds_locations": ListOf(PDSLocations(), doc="Statement ID 0.4.0.1862.1.5"),
   104          "retention_period": ListOf(Signed64BitInteger(), doc="Statement ID 0.4.0.1862.1.3"),
   105          "legislation": ListOf(QCLegislation(), doc="Statement ID 0.4.0.1862.1.7"),
   106      }, doc="Contains known QCStatements. Each field is repeated to handle the case where a single statement appears more than once."),
   107  })
   108  
   109  # x509/extensions.go: GeneralNames/jsonGeneralNames [RFC 5280 section 4.2.1.6]
   110  GeneralNames = SubRecordType({
   111      "dns_names": ListOf(FQDN(), doc="dNSName entries in the GeneralName (IA5String, CHOICE tag 2)."),
   112      "email_addresses": ListOf(EmailAddress(), doc="rfc822Name entries in the GeneralName (IA5String, CHOICE tag 1)."),
   113      "ip_addresses": ListOf(IPAddress(), doc="iPAddress entries in the GeneralName (CHOICE tag 7)."),
   114      "directory_names": ListOf(DistinguishedName(), doc="Parsed directoryName entries in the GeneralName (CHOICE tag 4)."),
   115      "edi_party_names": ListOf(EDIPartyName(), doc="Parsed eDIPartyName entries in the GeneralName (CHOICE tag 5)"),
   116      "other_names": ListOf(OtherName(), doc="otherName entries in the GeneralName (CHOICE tag 0). An arbitrary binary value identified by an OBJECT IDENTIFIER."),
   117      "registered_ids": ListOf(OID(), doc="registeredID entries in the GeneralName (OBJECT IDENTIFIER, CHOICE tag 8). Stored in dotted-decimal format."),
   118      "uniform_resource_identifiers": ListOf(URI(), doc="uniformResourceIdentifier entries in the GeneralName (CHOICE tag 6)."),
   119  }, doc="Parsed GeneralNames struct: component GeneralName values are grouped by their type. See RFC 5280 section 4.2.1.6.")
   120  
   121  # json/dhe.go: cryptoParameter / auxCryptoParameter
   122  CryptoParameter = SubRecordType({
   123      "value": IndexedBinary(required=False, doc="The value of the parameter."),
   124      "length": Unsigned16BitInteger(required=False, doc="The length of the parameter."),
   125  }, doc="Generic parameter for a cryptographic algorithm.")
   126  
   127  # json/dhe.go: DHParams / auxDHParams:
   128  DHParams = SubRecordType({
   129      "prime": CryptoParameter(doc="The shared prime number."),
   130      "generator": CryptoParameter(doc="The generator of the DH group."),
   131      "server_public": CryptoParameter(doc="The server's public key.", required=False),
   132      "server_private": CryptoParameter(doc="The server's private key. Usually does not coexist with client_private.", required=False),
   133      "client_public": CryptoParameter(doc="The client's public key.", required=False),
   134      "client_private": CryptoParameter(doc="The client's private key. Usually does not coexist with server_private.", required=False),
   135      "session_key": CryptoParameter(doc="The session key.", required=False),
   136  }, doc="Parameters for the Diffie-Hellman key exchange.")
   137  
   138  # json/rsa.go: RSAPublicKey/auxRSAPublicKey (alias for crypto/rsa/PublicKey)
   139  RSAPublicKey = SubRecordType({
   140      "exponent": Unsigned32BitInteger(doc="The RSA key's public exponent (e)."),
   141      "modulus": IndexedBinary(doc="The RSA key's modulus (n) in big-endian encoding."),
   142      "length": Unsigned16BitInteger(doc="Bit-length of modulus."),
   143  }, doc="Container for the public portion (modulus and exponent) of an RSA asymmetric key.")
   144  
   145  # json/rsa.go: RSAClientParams
   146  RSAClientParams = SubRecordType({
   147      "length": Unsigned16BitInteger(required=False, doc="Bit-length of modulus."),
   148      "encrypted_pre_master_secret": Binary(required=False, doc="The premaster secret encrypted with the server's public key."),
   149  }, doc="TLS key exchange parameters for RSA keys.")
   150  
   151  # json/names.go: ecIDToName
   152  tls_curve_id_names = [
   153      "unknown", "sect163k1", "sect163r1", "sect163r2",
   154      "sect193r1", "sect193r2", "sect233k1", "sect233r1", "sect239k1",
   155      "sect283k1", "sect283r1", "sect409k1", "sect409r1", "sect571k1",
   156      "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1",
   157      "secp192r1", "secp224k1", "secp224r1", "secp256k1", "secp256r1",
   158      "secp384r1", "secp521r1", "brainpoolp256r1", "brainpoolp384r1",
   159      "brainpoolp512r1"]
   160  
   161  # json/ecdhe.go: TLSCurveID.MarshalJSON()
   162  TLSCurveID = SubRecordType({
   163      "name": Enum(values=tls_curve_id_names, doc="The name of the curve algorithm (e.g. sect163kr1, secp192r1). Unrecognized curves are 'unknown'."),
   164      "id": Unsigned16BitInteger(doc="The numeric value of the curve identifier. See http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8"),
   165  }, doc="An elliptic curve algorithm identifier.")
   166  
   167  # json/ecdhe.go: ECPoint.MarshalJSON()
   168  ECPoint = SubRecordType({
   169      "x": CryptoParameter(required=False),
   170      "y": CryptoParameter(required=False),
   171  }, doc="An elliptic curve point.")
   172  
   173  # json/ecdhe.go: ECDHPrivateParams
   174  ECDHPrivateParams = SubRecordType({
   175      "value": IndexedBinary(required=False),
   176      "length": Unsigned16BitInteger(required=False),
   177  }, doc="TLS key exchange parameters for ECDH keys.")
   178  
   179  # json/ecdhe.go: ECDHParams
   180  ECDHParams = SubRecordType({
   181      "curve_id": TLSCurveID(required=False),
   182      "server_public": ECPoint(required=False),
   183      "server_private": ECDHPrivateParams(required=False),
   184      "client_public": ECPoint(required=False),
   185      "client_private": ECDHPrivateParams(required=False),
   186  }, doc="Parameters for ECDH key exchange.")
   187  
   188  # x509/json.go (mapped from crypto.dsa)
   189  DSAPublicKey = SubRecordType({
   190      "p": IndexedBinary(),
   191      "q": IndexedBinary(),
   192      "g": IndexedBinary(),
   193      "y": IndexedBinary(),
   194  }, doc="The public portion of a DSA asymmetric key.")
   195  
   196  # x509/json.go (mapped from crypto.ecdsa)
   197  ECDSAPublicKey = SubRecordType({
   198      "pub": IndexedBinary(),
   199      "b": IndexedBinary(),
   200      "gx": IndexedBinary(),
   201      "gy": IndexedBinary(),
   202      "n": IndexedBinary(),
   203      "p": IndexedBinary(),
   204      "x": IndexedBinary(),
   205      "y": IndexedBinary(),
   206      "curve": Enum(values=["P-224", "P-256", "P-384", "P-521"]),
   207      "length": Unsigned16BitInteger(),
   208      # schema conflict in censys prod cert index
   209      # "asn1_oid":OID(),
   210  }, doc="The public portion of an ECDSA asymmetric key.")
   211  
   212  # x509/ct/types.go: type Version uint8; "represents the Version enum from section 3.2 of the RFC: enum { v1(0), (255) } Version;"
   213  SCTVersion = Unsigned8BitInteger().with_args(doc="Version of the protocol to which the SCT conforms.", examples=[0, 255])
   214  
   215  # x509/ct/types.go: SignedCertificateTimestamp.
   216  # Note: ztag_sct has "log_name": String(), which is not present in the go.
   217  # Note: The timestamp is actually seconds, not milliseconds (as in the ASN.1 structure) -- in MarshalJSON it divides by 1000.
   218  SCTRecord = SubRecordType({
   219      "version": SCTVersion(),
   220      "log_id": IndexedBinary(doc="The SHA-256 hash of the log's public key, calculated over the DER encoding of the key's SubjectPublicKeyInfo."),
   221      "timestamp": Timestamp(doc="Time at which the SCT was issued (in seconds since the Unix epoch).", required=False),
   222      "extensions": Binary(doc="For future extensions to the protocol.", required=False),
   223      "signature": Binary(doc="The log's signature for this SCT."),
   224  }, doc="A parsed SignedCertificateTimestamp record (See RFC 6962 section 3.2).")
   225  
   226  # x509/json.go: auxGeneralSubtreeIP (modifies GeneralSubtreeIP from x509.go)
   227  GeneralSubtreeIP = SubRecordType({
   228      "cidr": String(doc="The CIDR specifying the subtree.", required=False),
   229      "begin": IPAddress(doc="The first IP in the range.", required=False),
   230      "end": IPAddress(doc="The last IP in the range.", required=False),
   231      "mask": IPAddress(doc="The mask IP.", required=False),
   232  }, exclude=["bigquery"], doc="A GeneralSubtree for GeneralName type of IP address.")  # XXX
   233  
   234  # x509/extensions.go: type NoticeReference struct
   235  NoticeReference = SubRecordType({
   236      # Note: these are both omitempty in the go code, but required in the ASN.1 spec.
   237      "organization": WhitespaceAnalyzedString(doc="The organization that prepared the notice.", required=False),
   238      "notice_numbers": ListOf(Signed32BitInteger(), required=False, doc="The numeric identifier(s) of the notice."),
   239  }, doc="A reference to a textual notice statement provided by an organization.")
   240  
   241  # x509/extensions.go: type UserNoticeData struct
   242  UserNoticeData = SubRecordType({
   243      "explicit_text": EnglishString(doc="Textual statement with a maximum size of 200 characters. Should be a UTF8String or IA5String.", required=False),
   244      # NOTE: We encode this as a slice, but it always has just one element (which makes sense, because the noticeRef is not a SEQUENCE in the ASN.1 spec).
   245      "notice_reference": ListOf(NoticeReference(), required=False, doc="Names an organization and identifies, by number, a particular textual statement prepared by that organization."),
   246  }, doc="Notice to display to relying parties when certificate is used.")
   247  
   248  # x509/extensions.go: type CertificatePoliciesJSON struct
   249  # TODO: ztag has a "name": String() field?
   250  CertificatePoliciesData = SubRecordType({
   251      "id": OID(doc="The OBJECT IDENTIFIER identifying the policy."),
   252      "cps": ListOf(URL(), doc="List of URIs to the policies"),
   253      # NOTE: In ztag, this was a single UserNoticeData, not a ListOf(UserNoticeData).
   254      # Chris's validation of ESLoader errors confirmed that this should in fact be a list.
   255      "user_notice": ListOf(UserNoticeData(), doc="List of textual notices to display relying parties."),
   256  })
   257  
   258  # Generated by zcrypto/x509/extended_key_usage_schema.sh, with a manual tweak on unknown
   259  ExtendedKeyUsage = SubRecordType({
   260      # NOTE: ztag has "value" with the comment "TODO: remove after reparse",
   261      # but there is no "value" in the JSON.
   262      "value": ListOf(Signed32BitInteger()),
   263      "any": Boolean(doc="Extension has extended key usage ANY (OBJECT IDENTIFIER = 2.5.29.37.0)"),
   264      "apple_code_signing": Boolean(doc="Extension has extended key usage APPLE_CODE_SIGNING (OBJECT IDENTIFIER = 1.2.840.113635.100.4.1)"),
   265      "apple_code_signing_development": Boolean(doc="Extension has extended key usage APPLE_CODE_SIGNING_DEVELOPMENT (OBJECT IDENTIFIER = 1.2.840.113635.100.4.1.1)"),
   266      "apple_code_signing_third_party": Boolean(doc="Extension has extended key usage APPLE_CODE_SIGNING_THIRD_PARTY (OBJECT IDENTIFIER = 1.2.840.113635.100.4.1.3)"),
   267      "apple_crypto_development_env": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_DEVELOPMENT_ENV (OBJECT IDENTIFIER = 1.2.840.113635.100.4.5.4)"),
   268      "apple_crypto_env": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_ENV (OBJECT IDENTIFIER = 1.2.840.113635.100.4.5)"),
   269      "apple_crypto_maintenance_env": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_MAINTENANCE_ENV (OBJECT IDENTIFIER = 1.2.840.113635.100.4.5.2)"),
   270      "apple_crypto_production_env": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_PRODUCTION_ENV (OBJECT IDENTIFIER = 1.2.840.113635.100.4.5.1)"),
   271      "apple_crypto_qos": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_QOS (OBJECT IDENTIFIER = 1.2.840.113635.100.4.6)"),
   272      "apple_crypto_test_env": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_TEST_ENV (OBJECT IDENTIFIER = 1.2.840.113635.100.4.5.3)"),
   273      "apple_crypto_tier0_qos": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_TIER0_QOS (OBJECT IDENTIFIER = 1.2.840.113635.100.4.6.1)"),
   274      "apple_crypto_tier1_qos": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_TIER1_QOS (OBJECT IDENTIFIER = 1.2.840.113635.100.4.6.2)"),
   275      "apple_crypto_tier2_qos": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_TIER2_QOS (OBJECT IDENTIFIER = 1.2.840.113635.100.4.6.3)"),
   276      "apple_crypto_tier3_qos": Boolean(doc="Extension has extended key usage APPLE_CRYPTO_TIER3_QOS (OBJECT IDENTIFIER = 1.2.840.113635.100.4.6.4)"),
   277      "apple_ichat_encryption": Boolean(doc="Extension has extended key usage APPLE_ICHAT_ENCRYPTION (OBJECT IDENTIFIER = 1.2.840.113635.100.4.3)"),
   278      "apple_ichat_signing": Boolean(doc="Extension has extended key usage APPLE_ICHAT_SIGNING (OBJECT IDENTIFIER = 1.2.840.113635.100.4.2)"),
   279      "apple_resource_signing": Boolean(doc="Extension has extended key usage APPLE_RESOURCE_SIGNING (OBJECT IDENTIFIER = 1.2.840.113635.100.4.1.4)"),
   280      "apple_software_update_signing": Boolean(doc="Extension has extended key usage APPLE_SOFTWARE_UPDATE_SIGNING (OBJECT IDENTIFIER = 1.2.840.113635.100.4.1.2)"),
   281      "apple_system_identity": Boolean(doc="Extension has extended key usage APPLE_SYSTEM_IDENTITY (OBJECT IDENTIFIER = 1.2.840.113635.100.4.4)"),
   282      "client_auth": Boolean(doc="Extension has extended key usage CLIENT_AUTH (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.2)"),
   283      "code_signing": Boolean(doc="Extension has extended key usage CODE_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.3)"),
   284      "dvcs": Boolean(doc="Extension has extended key usage DVCS (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.10)"),
   285      "eap_over_lan": Boolean(doc="Extension has extended key usage EAP_OVER_LAN (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.14)"),
   286      "eap_over_ppp": Boolean(doc="Extension has extended key usage EAP_OVER_PPP (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.13)"),
   287      "email_protection": Boolean(doc="Extension has extended key usage EMAIL_PROTECTION (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.4)"),
   288      "ipsec_end_system": Boolean(doc="Extension has extended key usage IPSEC_END_SYSTEM (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.5)"),
   289      "ipsec_tunnel": Boolean(doc="Extension has extended key usage IPSEC_TUNNEL (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.6)"),
   290      "ipsec_user": Boolean(doc="Extension has extended key usage IPSEC_USER (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.7)"),
   291      "microsoft_ca_exchange": Boolean(doc="Extension has extended key usage MICROSOFT_CA_EXCHANGE (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.21.5)"),
   292      "microsoft_cert_trust_list_signing": Boolean(doc="Extension has extended key usage MICROSOFT_CERT_TRUST_LIST_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.1)"),
   293      "microsoft_csp_signature": Boolean(doc="Extension has extended key usage MICROSOFT_CSP_SIGNATURE (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.16)"),
   294      "microsoft_document_signing": Boolean(doc="Extension has extended key usage MICROSOFT_DOCUMENT_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.12)"),
   295      "microsoft_drm": Boolean(doc="Extension has extended key usage MICROSOFT_DRM (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.5.1)"),
   296      "microsoft_drm_individualization": Boolean(doc="Extension has extended key usage MICROSOFT_DRM_INDIVIDUALIZATION (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.5.2)"),
   297      "microsoft_efs_recovery": Boolean(doc="Extension has extended key usage MICROSOFT_EFS_RECOVERY (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.4.1)"),
   298      "microsoft_embedded_nt_crypto": Boolean(doc="Extension has extended key usage MICROSOFT_EMBEDDED_NT_CRYPTO (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.8)"),
   299      "microsoft_encrypted_file_system": Boolean(doc="Extension has extended key usage MICROSOFT_ENCRYPTED_FILE_SYSTEM (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.4)"),
   300      "microsoft_enrollment_agent": Boolean(doc="Extension has extended key usage MICROSOFT_ENROLLMENT_AGENT (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.20.2.1)"),
   301      "microsoft_kernel_mode_code_signing": Boolean(doc="Extension has extended key usage MICROSOFT_KERNEL_MODE_CODE_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.61.1.1)"),
   302      "microsoft_key_recovery_21": Boolean(doc="Extension has extended key usage MICROSOFT_KEY_RECOVERY_21 (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.21.6)"),
   303      "microsoft_key_recovery_3": Boolean(doc="Extension has extended key usage MICROSOFT_KEY_RECOVERY_3 (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.11)"),
   304      "microsoft_license_server": Boolean(doc="Extension has extended key usage MICROSOFT_LICENSE_SERVER (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.5.4)"),
   305      "microsoft_licenses": Boolean(doc="Extension has extended key usage MICROSOFT_LICENSES (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.5.3)"),
   306      "microsoft_lifetime_signing": Boolean(doc="Extension has extended key usage MICROSOFT_LIFETIME_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.13)"),
   307      "microsoft_mobile_device_software": Boolean(doc="Extension has extended key usage MICROSOFT_MOBILE_DEVICE_SOFTWARE (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.14)"),
   308      "microsoft_nt5_crypto": Boolean(doc="Extension has extended key usage MICROSOFT_NT5_CRYPTO (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.6)"),
   309      "microsoft_oem_whql_crypto": Boolean(doc="Extension has extended key usage MICROSOFT_OEM_WHQL_CRYPTO (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.7)"),
   310      "microsoft_qualified_subordinate": Boolean(doc="Extension has extended key usage MICROSOFT_QUALIFIED_SUBORDINATE (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.10)"),
   311      "microsoft_root_list_signer": Boolean(doc="Extension has extended key usage MICROSOFT_ROOT_LIST_SIGNER (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.9)"),
   312      "microsoft_server_gated_crypto": Boolean(doc="Extension has extended key usage MICROSOFT_SERVER_GATED_CRYPTO (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.3)"),
   313      "microsoft_sgc_serialized": Boolean(doc="Extension has extended key usage MICROSOFT_SGC_SERIALIZED (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.3.1)"),
   314      "microsoft_smart_display": Boolean(doc="Extension has extended key usage MICROSOFT_SMART_DISPLAY (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.15)"),
   315      "microsoft_smartcard_logon": Boolean(doc="Extension has extended key usage MICROSOFT_SMARTCARD_LOGON (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.20.2.2)"),
   316      "microsoft_system_health": Boolean(doc="Extension has extended key usage MICROSOFT_SYSTEM_HEALTH (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.47.1.1)"),
   317      "microsoft_system_health_loophole": Boolean(doc="Extension has extended key usage MICROSOFT_SYSTEM_HEALTH_LOOPHOLE (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.47.1.3)"),
   318      "microsoft_timestamp_signing": Boolean(doc="Extension has extended key usage MICROSOFT_TIMESTAMP_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.2)"),
   319      "microsoft_whql_crypto": Boolean(doc="Extension has extended key usage MICROSOFT_WHQL_CRYPTO (OBJECT IDENTIFIER = 1.3.6.1.4.1.311.10.3.5)"),
   320      "netscape_server_gated_crypto": Boolean(doc="Extension has extended key usage NETSCAPE_SERVER_GATED_CRYPTO (OBJECT IDENTIFIER = 2.16.840.1.113730.4.1)"),
   321      "ocsp_signing": Boolean(doc="Extension has extended key usage OCSP_SIGNING (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.9)"),
   322      "sbgp_cert_aa_service_auth": Boolean(doc="Extension has extended key usage SBGP_CERT_AA_SERVICE_AUTH (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.11)"),
   323      "server_auth": Boolean(doc="Extension has extended key usage SERVER_AUTH (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.1)"),
   324      "time_stamping": Boolean(doc="Extension has extended key usage TIME_STAMPING (OBJECT IDENTIFIER = 1.3.6.1.5.5.7.3.8)"),
   325  
   326      # NOTE: ztag has this commented out, but it is included in the JSON.
   327      "unknown": ListOf(OID(), doc="A list of the raw OBJECT IDENTIFIERs of any EKUs not recognized by the application."),
   328  }, category="Extended Key Usage", validation_policy="warn")
   329  
   330  # x509/json.go: auxPublicKeyAlgorithm (via PublicKeyAlgorithm)
   331  PublicKeyAlgorithm = SubRecordType({
   332      "name": String(doc="Name of public key type, e.g., RSA or ECDSA. "\
   333                         "More information is available the named SubRecord "\
   334                         "(e.g., RSAPublicKey())."),
   335      "oid": OID(doc="OID of the public key on the certificate. "\
   336                     "This is helpful when an unknown type is present. "\
   337                     "This field is reserved and not currently populated.",
   338                 validation_policy="warn")
   339  })
   340  
   341  # x509/json.go: auxSignatureAlgorithm (via SignatureAlgorithm)
   342  SignatureAlgorithm = SubRecordType({
   343      "name": String(doc="Name of signature algorithm, e.g., SHA1-RSA or "\
   344                         "ECDSA-SHA512. Unknown algorithms get an integer id."),
   345      "oid": OID(doc="The OBJECT IDENTIFIER of the signature algorithm, in "\
   346                     "dotted-decimal notation.", validation_policy="warn")
   347  })
   348  
   349  # x509/extensions.go: type SubjAuthKeyId []byte (but, its MarshalJSON returns json.Marshal(hex.EncodeToString(kid)))
   350  SubjAuthKeyId = HexString.with_args(doc="A key identifier, usually a digest of the DER encoding of a SubjectPublicKeyInfo. This is the hex encoding of the OCTET STRING value.")
   351  
   352  # x509/json.go jsonCertificate (mapped from x509.Certificate)
   353  ParsedCertificate = SubRecordType({
   354      "subject": DistinguishedName(category="Subject", doc="The parsed subject name."),
   355      "subject_dn": WhitespaceAnalyzedString(category="Basic Information", doc="A canonical string representation of the subject name.", examples=["C=US, ST=MI, L=Ann Arbor, OU=Scans, CN=localhost, emailAddress=root@localhost"]),
   356      "issuer": DistinguishedName(category="Issuer", doc="The parsed issuer name."),
   357      "issuer_dn": WhitespaceAnalyzedString(category="Basic Information", doc="A canonical string representation of the issuer name.", examples=["C=US, ST=MI, L=Ann Arbor, OU=Certificate authority, CN=CA1, emailAddress=ca1@localhost"]),
   358      "version": Unsigned8BitInteger(category="Misc", doc="The x.509 certificate version number."),
   359      # NOTE: This is indeed encoded as a base 10 string via math.big.int.Text(10)
   360      "serial_number": String(doc="Serial number as an signed decimal integer. "\
   361                                  "Stored as string to support >uint lengths. "\
   362                                  "Negative values are allowed.",
   363                                  category="Basic Information"),
   364      "validity": SubRecord({
   365          "start": Timestamp(doc="Timestamp of when certificate is first valid. Timezone is UTC."),
   366          "end": Timestamp(doc="Timestamp of when certificate expires. Timezone is UTC."),
   367          "length": Signed64BitInteger(doc="The length of time, in seconds, that the certificate is valid."),
   368      }, category="Validity Period"),
   369      "signature_algorithm": SignatureAlgorithm(doc="Identifies the algorithm used by the CA to sign the certificate.", category="Signature"),
   370      "subject_key_info": SubRecord({
   371          "fingerprint_sha256": HexString(doc="The SHA2-256 digest calculated over the certificate's DER-encoded SubjectPublicKeyInfo field."),
   372          "key_algorithm": PublicKeyAlgorithm(doc="Identifies the type of key and any relevant parameters."),
   373          "rsa_public_key": RSAPublicKey(),
   374          "dsa_public_key": DSAPublicKey(),
   375          "ecdsa_public_key": ECDSAPublicKey(),
   376      }, category="Public Key", doc="The certificate's public key. Only one of the *_public_key fields will be set."),
   377      "extensions": SubRecord({
   378          "key_usage": SubRecord({
   379              "value": Unsigned16BitInteger(doc="Integer value of the bitmask in the extension"),
   380              "digital_signature": Boolean(doc="Indicates if the digitalSignature bit(0) is set."),
   381              "certificate_sign": Boolean(doc="Indicates if the keyCertSign bit(5) is set."),
   382              "crl_sign": Boolean(doc="Indicates if the cRLSign bit(6) is set."),
   383              "content_commitment": Boolean(doc="Indicates if the contentCommitment bit(1) (formerly called nonRepudiation) is set."),
   384              "key_encipherment": Boolean(doc="Indicates if the keyEncipherment bit(2) is set."),
   385              "data_encipherment": Boolean(doc="Indicates if the dataEncipherment bit(3) is set."),
   386              "key_agreement": Boolean(doc="Indicates if the keyAgreement bit(4) is set."),
   387              "decipher_only": Boolean(doc="Indicates if the encipherOnly bit(7) is set."),
   388              "encipher_only": Boolean(doc="Indicates if the decipherOnly bit(8) is set."),
   389          }, category="Key Usage", doc="The parsed id-ce-keyUsage extension (2.5.29.15); see RFC 5280."),
   390          "basic_constraints": SubRecord({
   391              "is_ca": Boolean(doc="Indicates that the certificate is permitted to sign other certificates."),
   392              "max_path_len": Signed32BitInteger(doc="When present, gives the  maximum number of non-self-issued intermediate certificates that may follow this certificate in a valid certification path."),
   393          }, category="Basic Constraints", doc="The parsed id-ce-basicConstraints extension (2.5.29.19); see RFC 5280."),
   394          "subject_alt_name": GeneralNames(category="Subject Alternate Names (SANs)", doc="The parsed Subject Alternative Name extension (id-ce-subjectAltName, 2.5.29.17).", required=False),
   395          "issuer_alt_name": GeneralNames(category="Issuer Alternate Names (IANs)", doc="The parsed Issuer Alternative Name extension (id-ce-issuerAltName, 2.5.29.18).", required=False),
   396          "crl_distribution_points": ListOf(URL(), category="CRL Distribution Points", doc="The parsed id-ce-cRLDistributionPoints extension (2.5.29.31). Contents are a list of distributionPoint URLs (other distributionPoint types are omitted)."),
   397          # NOTE: inherit the SubjAuthKeyId docs
   398          "authority_key_id": SubjAuthKeyId(category="Authority Key ID (AKID)"),
   399          "subject_key_id": SubjAuthKeyId(category="Subject Key ID (SKID)", validation_policy="warn"),
   400          "extended_key_usage": ExtendedKeyUsage(doc="The parsed id-ce-extKeyUsage (2.5.29.37) extension."),
   401          "certificate_policies": ListOf(CertificatePoliciesData(), category="Certificate Policies", validation_policy="warn", doc="The parsed id-ce-certificatePolicies extension (2.5.29.32)."),
   402          "authority_info_access": SubRecord({
   403              "ocsp_urls": ListOf(URL(), doc="URLs of accessLocations with accessMethod of id-ad-ocsp, pointing to OCSP servers that can be used to check this certificate's revocation status. Only uniformResourceIdentifier accessLocations are supported; others are omitted."),
   404              "issuer_urls": ListOf(URL(), doc="URLs of accessLocations with accessMethod of id-ad-caIssuers, pointing to locations where this certificate's issuers can be downloaded. Only uniformResourceIdentifier accessLocations are supported; others are omitted."),
   405          }, category="Authority Info Access (AIA)", doc="The parsed id-pe-authorityInfoAccess extension (1.3.6.1.5.7.1.1). Only id-ad-caIssuers and id-ad-ocsp accessMethods are supported; others are omitted."),
   406          "name_constraints": SubRecord({
   407              "critical": Boolean(doc="If set, clients unable to understand this extension must reject this certificate."),
   408              "permitted_names": ListOf(FQDN(), doc="Permitted names of type dNSName."),
   409              # We do not schema email addresses as an EmailAddress per
   410              # rfc5280#section-4.2.1.10 documentation:
   411              # A name constraint for Internet mail addresses MAY specify a
   412              # particular mailbox, all addresses at a particular host, or all
   413              # mailboxes in a domain.  To indicate a particular mailbox, the
   414              # constraint is the complete mail address.  For example,
   415              # "root@example.com" indicates the root mailbox on the host
   416              # "example.com".  To indicate all Internet mail addresses on a
   417              # particular host, the constraint is specified as the host name.  For
   418              # example, the constraint "example.com" is satisfied by any mail
   419              # address at the host "example.com".  To specify any address within a
   420              # domain, the constraint is specified with a leading period (as with
   421              # URIs).  For example, ".example.com" indicates all the Internet mail
   422              # addresses in the domain "example.com", but not Internet mail
   423              # addresses on the host "example.com".
   424              "permitted_email_addresses": ListOf(WhitespaceAnalyzedString(), doc="Permitted names of type rfc822Name."),
   425              "permitted_ip_addresses": ListOf(GeneralSubtreeIP(), doc="Range of permitted names of type iPAddress."),
   426              "permitted_directory_names": ListOf(DistinguishedName(), doc="Permitted names of type directoryName."),
   427              "permitted_registered_ids": ListOf(OID(), doc="Permitted names of type registeredID."),
   428              "permitted_edi_party_names": ListOf(EDIPartyName(), doc="Permitted names of type ediPartyName"),
   429              "excluded_names": ListOf(FQDN(), doc="Excluded names of type dNSName."),
   430              "excluded_email_addresses": ListOf(WhitespaceAnalyzedString(), doc="Excluded names of type rfc822Name."),
   431              "excluded_ip_addresses": ListOf(GeneralSubtreeIP(), doc="Range of excluded names of type iPAddress."),
   432              "excluded_directory_names": ListOf(DistinguishedName(), doc="Excluded names of type directoryName."),
   433              "excluded_registered_ids": ListOf(OID(), doc="Excluded names of type registeredID."),
   434              "excluded_edi_party_names": ListOf(EDIPartyName(), doc="Excluded names of type ediPartyName."),
   435          }, category="Name Constraints", doc="The parsed id-ce-nameConstraints extension (2.5.29.30). Specifies a name space within which all child certificates' subject names MUST be located."),
   436          "signed_certificate_timestamps": ListOf(SCTRecord(), category="Embedded SCTS / CT Poison", doc="The parsed Certificate Transparency SignedCertificateTimestampsList extension (1.3.6.1.4.1.11129.2.4.2); see RFC 6962."),
   437          "ct_poison": Boolean(category="Embedded SCTS / CT Poison", doc="This is true if the certificate possesses the Certificate Transparency Precertificate Poison extension (1.3.6.1.4.1.11129.2.4.3)."),
   438          "cabf_organization_id": CABFOrganizationID(category="CABF Organization ID Extension", doc="The CA/BF organization ID extensions (2.23.140.3.1)"),
   439          "qc_statements": QCStatementsExtensions(category="QC Statements Extension", doc="IDs and parsed statements for qualified certificates (1.3.6.1.5.5.7.1.3)"),
   440      }),
   441      "unknown_extensions": ListOf(UnknownExtension(), category="Unknown Extensions", doc="List of raw extensions that were not recognized by the application."),
   442      "signature": SubRecord({
   443          "signature_algorithm": SignatureAlgorithm(),
   444          "value": Binary(doc="Contents of the signature BIT STRING."),
   445          "valid": Boolean(),
   446          "self_signed": Boolean(doc="Indicates whether the subject key was also used to sign the certificate."),
   447      }, category="Signature"),
   448      "fingerprint_md5": HexString(category="Fingerprint", doc="The MD5 digest over the DER encoding of the certificate, as a hexadecimal string."),
   449      "fingerprint_sha1": HexString(category="Fingerprint", doc="The SHA1 digest over the DER encoding of the certificate, as a hexadecimal string."),
   450      "fingerprint_sha256": HexString(category="Fingerprint", doc="The SHA2-256 digest over the DER encoding of the certificate, as a hexadecimal string."),
   451      "spki_subject_fingerprint": HexString(category="Fingerprint", doc="The SHA2-256 digest over the DER encoding of the certificate's SubjectPublicKeyInfo, as a hexadecimal string."),
   452      "tbs_fingerprint": HexString(category="Fingerprint", doc="The SHA2-256 digest over the DER encoding of the certificate's TBSCertificate, as a hexadecimal string."),
   453      "tbs_noct_fingerprint": HexString(category="Fingerprint", doc="The SHA2-256 digest over the DER encoding of the certificate's TBSCertificate, *with any CT extensions omitted*, as a hexadecimal string."),
   454      "names": ListOf(FQDN(), category="Basic Information", doc="A list of subject names in the certificate, including the Subject CommonName and SubjectAltName DNSNames, IPAddresses and URIs."),
   455      # NOTE: ztag has "__expanded_names": ListOf(String())
   456      # Calculated in parseCertificate() in x509.go
   457      "validation_level": Enum(values=["unknown", "DV", "OV", "EV"], category="Misc", doc="How the certificate is validated -- Domain validated (DV), Organization Validated (OV), Extended Validation (EV), or unknown."),
   458      "redacted": Boolean(category="Misc", doc="This is set if any of the certificate's names contain redacted fields."),
   459  })
   460  
   461  # x509/validation.go: Validation
   462  CertValidationResult = SubRecordType({
   463      "browser_trusted": Boolean(doc="If true, the certificate was valid and chained to a browser root CA."),
   464      "browser_error": String(doc="If browser_trusted is false, this may give more information about the failure."),
   465      "matches_domain": Boolean(doc="If true, validation was provided with a hostname that matched the one of the certificate's names.")
   466  })
   467  
   468  # tls/tls_handshake.go: SimpleCertificate
   469  SimpleCertificate = SubRecordType({
   470      "raw": Binary(doc="The DER encoding of the certificate."),
   471      "parsed": ParsedCertificate(doc="The parsed certificate."),
   472      "validation": CertValidationResult(doc="If present, the results of checking the certificate's validity."),
   473  })
   474  
   475  ###### END ztag/zgrab ######
   476  
   477  # TODO: Should any of these be IndexedBinary() / WhitespaceAnalyzedString()?
   478  
   479  GoInt = Signed32BitInteger
   480  
   481  # tls/tls_handshake.go: CipherSuite (uint16)
   482  CipherSuite = SubRecordType({
   483      "hex": String(doc="The hexadecimal encoding of the numeric cipher suite identifier, prefixed with 0x.", examples=["0x0", "0x10", "0x100", "0xCAFE"]),
   484      # TODO: Enum()? There are a ton of these; from cipherSuiteNames in tls_names.go.
   485      "name": String(doc="The const name of the cipher suite. See e.g. https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml.", examples=["unknown", "TLS_RSA_WITH_RC4_128_MD5", "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256"]),
   486      "value": Unsigned16BitInteger(doc="The numerical value of the cipher suite identifier."),
   487  })
   488  
   489  # tls/tls_handshake.go: CompressionMethod (uint8)
   490  CompressionMethod = SubRecordType({
   491      "hex": String(doc="The hexadecimal encoding of the numeric compression method identifier, prefixed with 0x.", examples=["0x0", "0x1", "0x40", "0xFF"]),
   492      "name": Enum(doc="The const name of the compression method; see https://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml#comp-meth-ids-2.", values=["NULL", "DEFLATE", "LZS", "unknown"]),
   493      "value": Unsigned8BitInteger(doc="The numerical value of the compression method identifier."),
   494  })
   495  
   496  signature_algorithm_names = getUnknowns({
   497      # 0: "anonymous",
   498      1: "rsa",
   499      2: "dsa",
   500      3: "ecdsa",
   501      # 255: "",
   502  }, range(0, 256), lambda x: "unknown." + str(x))
   503  
   504  hash_algorithm_names = getUnknowns({
   505      # 0: "none",
   506      1: "md5",
   507      2: "sha1",
   508      3: "sha224",
   509      4: "sha256",
   510      5: "sha384",
   511      6: "sha512",
   512      # 255: "",
   513  }, range(0, 256), lambda x: "unknown." + str(x))
   514  
   515  # tls/tls_ka.go: auxSignatureAndHash (SignatureAndHash)
   516  SignatureAndHash = SubRecordType({
   517      # Defined in tls_names.go (signatureNames).
   518      "signature_algorithm": Enum(values=list(signature_algorithm_names.values()), doc="The name of the signature algorithm, as defined in RFC5246 section 7.4.1.4.1. Unrecognized values are of the form 'unknown.255'."),
   519      "hash_algorithm": Enum(values=list(hash_algorithm_names.values()), doc="The name of the hash algorithm, as defined in RFC5246 section 7.4.1.4.1. Unrecognized values are of the form 'unknown.255'."),
   520  }, doc="mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See RFC 5246, section A.4.1.")
   521  
   522  # tls_names.go: TLSVersion.String()
   523  TLSVersionName = Enum.with_args(values=["SSLv3", "TLSv1.0", "TLSv1.1", "TLSv1.2", "unknown"], doc="A human-readable version of the TLS version.")
   524  
   525  # tls/tls_handshake.go: type TLSVersion uint16 (marshal -> name/value)
   526  TLSVersion = SubRecordType({
   527      "name": TLSVersionName(),
   528      # Note -- this is an "int" (at least 32 bits) in the go struct, but the value itself is 16 bits.
   529      "value": Unsigned16BitInteger(doc="The TLS version identifier."),
   530  })
   531  
   532  # tls/tls_handshake.go: type SessionTicket
   533  SessionTicket = SubRecordType({
   534      "value": Binary(doc="The session ticket (an opaque binary blob)."),
   535      # Note -- this is an "int" in the go struct, but the length of the ticket is defined to be in [0, 2^16-1] in RFC 5077 section 3.3.
   536      "length": Unsigned16BitInteger(doc="The length of the session ticket, in bytes."),
   537      "lifetime_hint": Unsigned32BitInteger(doc="A hint from the server as to how long the ticket should be stored (in seconds relative to when the ticket is received)."),
   538  })
   539  
   540  # curveNames from tls_names.go, via https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
   541  curve_id_names = {
   542      1: "sect163k1",
   543      2: "sect163r1",
   544      3: "sect163r2",
   545      4: "sect193r1",
   546      5: "sect193r2",
   547      6: "sect233k1",
   548      7: "sect233r1",
   549      8: "sect239k1",
   550      9: "sect283k1",
   551      10: "sect283r1",
   552      11: "sect409k1",
   553      12: "sect409r1",
   554      13: "sect571k1",
   555      14: "sect571r1",
   556      15: "secp160k1",
   557      16: "secp160r1",
   558      17: "secp160r2",
   559      18: "secp192k1",
   560      19: "secp192r1",
   561      20: "secp224k1",
   562      21: "secp224r1",
   563      22: "secp256k1",
   564      23: "secp256r1",
   565      24: "secp384r1",
   566      25: "secp521r1",
   567      26: "brainpoolP256r1",
   568      27: "brainpoolP384r1",
   569      28: "brainpoolP512r1",
   570      29: "ecdh_x25519",
   571      30: "ecdh_x448",
   572      256: "ffdhe2048",
   573      257: "ffdhe3072",
   574      258: "ffdhe4096",
   575      259: "ffdhe6144",
   576      260: "ffdhe8192",
   577      65281: "arbitrary_explicit_prime_curves",
   578      65282: "arbitrary_explicit_char2_curves",
   579  }
   580  
   581  # tls/common.go: CurveID
   582  # Not to be confused with TLSCurveID from json/ecdhe.go.
   583  CurveID = SubRecordType({
   584      "hex": String(doc="The hexadecimal encoding of the numeric curve identifier, left-padded with zeroes, prefixed with 0x.", examples=["0x0001", "0x0026", "0xFF01"]),
   585      "name": Enum(values=list(curve_id_names.values()), doc="The enum name of the identified curve; see http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8."),
   586      "value": Unsigned16BitInteger(doc="The numerical value of the curve identifier."),
   587  })
   588  
   589  # tls/common.go: PointFormat
   590  PointFormat = SubRecordType({
   591      "hex": String(doc="The hexadecimal encoding of the numeric point format identifier, left-padded with zeroes, prefixed with 0x.", examples=["0x00"]),
   592      "name": Enum(values=["unknown", "uncompressed", "ansiX962_compressed_prime", "ansiX962_compressed_char2"], doc="The enum name of the identified point format; see https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9."),
   593      "value": Unsigned8BitInteger(doc="The numerical value of the point format identifier."),
   594  })
   595  
   596  # tls/tls_handshake.go: ClientHello
   597  ClientHello = SubRecordType({
   598      "version": TLSVersion(doc="The version of the TLS protocol by which the client wishes to communicate during this session."),
   599      "random": Binary(doc="A client-generated random structure."),
   600      "session_id": Binary(doc="The ID of a session the client wishes to use for this connection. This field is empty if no session_id is available, or if the client wishes to generate new security parameters."),
   601      "cipher_suites": ListOf(CipherSuite(), doc="A list of the cryptographic options supported by the client, ordered by client preference."),
   602      "compression_methods": ListOf(CompressionMethod(), doc="A list of the compression methods supported by the client, sorted by client preference."),
   603      "ocsp_stapling": Boolean(doc="This is true if the OCSP Stapling extension is set (see https://www.ietf.org/rfc/rfc6961.txt for details)."),
   604      "ticket": Boolean(doc="This is true if the client has the Session Ticket extension (see https://tools.ietf.org/html/rfc5077)."),
   605      "secure_renegotiation": Boolean(doc="This is true if the client has the Secure Renegotiation extension (see https://tools.ietf.org/html/rfc5746)."),
   606      "heartbeat": Boolean(doc="This is true if the client has the Heartbeat Supported extension (see https://tools.ietf.org/html/rfc6520)."),
   607      "extended_random": Binary(doc="The value of the Extended Random extension, if present (see https://tools.ietf.org/html/draft-rescorla-tls-extended-random-02)."),
   608      "extended_master_secret": Boolean(doc="This is true if the client has the Extended Master Secret extension (see https://tools.ietf.org/html/rfc7627)."),
   609      "next_protocol_negotiation": Boolean(doc="This is true if the client has the Next Protocol Negotiation extension (see https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-03.html)."),
   610      "server_name": String(doc="This contains the server name from the Server Name Identification (SNI) extension, if present (see https://tools.ietf.org/html/rfc6066#section-3)."),
   611      "scts": Boolean(doc="This is true if the client has the Signed Certificate Timestamp extension, if present (see https://tools.ietf.org/html/rfc6962#section-3.3.1)"),
   612      "supported_curves": ListOf(CurveID(), doc="The list of supported curves in the Supported Elliptic Curves extension, if present (see https://tools.ietf.org/html/rfc4492#section-5.1.1)"),
   613      "supported_point_formats": ListOf(PointFormat(), doc="The list of supported elliptic curve point formats in the Supported Point Formats extension, if present (see https://tools.ietf.org/html/rfc4492#section-5.1.2)."),
   614      "session_ticket": SessionTicket(doc="The session ticket in the Session Ticket extension, if present (see https://tools.ietf.org/html/rfc5077)."),
   615      "signature_and_hashes": ListOf(SignatureAndHash(), doc="The value of the signature_algorithms extension, if present (see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1)."),
   616      "sct_enabled": Boolean(doc="This is true if the client has the Signed Certificate Timestamp extension (see https://tools.ietf.org/html/rfc6962#section-3.3.1)."),
   617      "alpn_protocols": ListOf(String(), "This contains the list of protocols in the Application-Layer Protocol Negotiation extension, if present (see https://tools.ietf.org/html/rfc7301)."),
   618      "unknown_extensions": ListOf(Binary(), doc="A list of any unrecognized extensions in raw form."),
   619  }, doc="The Client Hello message (see https://tools.ietf.org/html/rfc5246#section-7.4.1.2).")
   620  
   621  # tls/tls_handshake.go: ServerHello
   622  ServerHello = SubRecordType({
   623      "version": TLSVersion(doc="This field will contain the lower of that suggested by the client in the client hello and the highest supported by the server."),
   624      "random": Binary(doc="This structure is generated by the server and MUST be independently generated from the ClientHello.random."),
   625      "session_id": Binary(doc="This is the identity of the session corresponding to this connection."),
   626      "cipher_suite": CipherSuite(doc="The single cipher suite selected by the server from the list in ClientHello.cipher_suites."),
   627      # TODO FIXME: This is a uint8 in the go code, but it should probably be a CompressionMethod...?
   628      "compression_method": Unsigned8BitInteger(doc="The single compression algorithm selected by the server from the list in ClientHello.compression_methods."),
   629      "ocsp_stapling": Boolean(doc="This is true if the OCSP Stapling extension is set (see https://www.ietf.org/rfc/rfc6961.txt for details)."),
   630      "ticket": Boolean(doc="This is true if the server has the Session Ticket extension (see https://tools.ietf.org/html/rfc5077)."),
   631      "secure_renegotiation": Boolean(doc="This is true if the client has the Secure Renegotiation extension (see https://tools.ietf.org/html/rfc5746)."),
   632      "heartbeat": Boolean(doc="This is true if the client has the Heartbeat Supported extension (see https://tools.ietf.org/html/rfc6520)."),
   633      "extended_random": Binary(doc="The value of the Extended Random extension, if present (see https://tools.ietf.org/html/draft-rescorla-tls-extended-random-02)."),
   634      "extended_master_secret": Boolean(doc="This is true if the server has the Extended Master Secret extension (see https://tools.ietf.org/html/rfc7627)."),
   635      "scts": ListOf(SubRecord({
   636          "parsed": SCTRecord(),
   637          "raw": Binary(),
   638      }), doc="The values in the SignedCertificateTimestampList of the Signed Certificate Timestamp, if present."),
   639  }, doc="The Server Hello message (see https://tools.ietf.org/html/rfc5246#section-7.4.1.3).")
   640  
   641  # tls/tls_handshake.go: ServerKeyExchange
   642  ServerKeyExchange = SubRecordType({
   643      "ecdh_params": ECDHParams(),
   644      "rsa_params": RSAPublicKey(),
   645      "dh_params": DHParams(),
   646      "digest": Binary(doc="The digest that is signed."),
   647      "signature": SubRecord({
   648          "raw": Binary(),
   649          "type": String(),
   650          "valid": Boolean(),
   651          "signature_and_hash_type": SignatureAndHash(),
   652          "tls_version": TLSVersion(),
   653      }),
   654      "signature_error": String(doc="The signature error, if one occurred."),
   655  }, doc="The key data sent by the server in the TLS key exchange message.")
   656  
   657  # tls/tls_handshake.go: ClientKeyExchange
   658  ClientKeyExchange = SubRecordType({
   659      "dh_params": DHParams(),
   660      "ecdh_params": ECDHParams(),
   661      "rsa_params": RSAClientParams(),
   662  }, doc="The key data sent by the client in the TLS key exchange message.")
   663  
   664  # tls/tls_handshake.go: MasterSecret
   665  MasterSecret = SubRecordType({
   666      "value": Binary(),
   667      "length": GoInt(),
   668  }, doc="The TLS master secret derived from the premaster secret (see e.g. RFC 5246 section 8.1).")
   669  
   670  # tls/tls_handshake.go: PreMasterSecret
   671  PreMasterSecret = SubRecordType({
   672      "value": Binary(),
   673      "length": GoInt(),
   674  }, doc="The TLS premaster secret used to during TLS key agreement to arrive at a master secret (see e.g. RFC 5246 section 8.1).")
   675  
   676  # tls/tls_handshake.go: KeyMaterial
   677  KeyMaterial = SubRecordType({
   678      "pre_master_secret": PreMasterSecret(),
   679      "master_secret": MasterSecret(),
   680  }, doc="The cryptographic values negotiated by the client and server.")
   681  
   682  # x509/validation.go: type Validation struct
   683  TLSCertificateValidation = SubRecordType({
   684      "matches_domain": Boolean(doc="Indicates whether the server's domain name matches that in the certificate."),
   685      #"stores":SubRecord({
   686      #    "nss":zgrab_server_certificate_valid,
   687      #    "microsoft":zgrab_server_certificate_valid,
   688      #    "apple":zgrab_server_certificate_valid,
   689      #    "java":zgrab_server_certificate_valid,
   690      #    "android":zgrab_server_certificate_valid,
   691      #})
   692      "browser_trusted": Boolean(doc="Indicates whether the certificate is trusted by the standard browser certificate stores."),
   693      "browser_error": String(doc="Description of the reason browser_trusted == false.")
   694  })
   695  
   696  # tls/tls_handshake.go: ServerHandshake
   697  # Note: docs inherited where possible
   698  TLSHandshake = SubRecordType({
   699      "client_hello": ClientHello(),
   700      "server_hello": ServerHello(),
   701      "server_certificates": SubRecord({
   702          "certificate": SimpleCertificate(),
   703          "chain": ListOf(SimpleCertificate()),
   704          "validation": TLSCertificateValidation(),
   705      }, doc="The certificates returned by the server, and their validation information."),
   706      "server_key_exchange": ServerKeyExchange(),
   707      "server_finished": SubRecord({
   708          "verify_data": Binary(doc="Data proving that the server has the correct parameters and secret data.")
   709      }, doc="The server's Finished message."),
   710      "session_ticket": SessionTicket(),
   711      "key_material": KeyMaterial(),
   712      "client_finished": SubRecord({
   713          "verify_data": Binary()
   714      }),
   715      "client_key_exchange": ClientKeyExchange(),
   716  })
   717  
   718  # zcrypto/tls/tls_heartbeat.go: Heartbleed
   719  HeartbleedLog = SubRecordType({
   720      "heartbeat_enabled": Boolean(doc="Indicates whether the server has the heatbeat extension enabled."),
   721      "heartbleed_vulnerable": Boolean(doc="Indicates whether the server is vulnerable to the Heartbleed attack.")
   722  })
   723  
   724  # zcrypto/x509/chain.go: type CertificateChain []*Certificate
   725  certificate_chain = ListOf(ParsedCertificate(), doc="Certificates used in validating another certificate.")