Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -2072,25 +2072,31 @@ if (objc == 2) { peer = SSL_get_peer_certificate(statePtr->ssl); } else { peer = SSL_get_certificate(statePtr->ssl); } + /* Get X509 certificate info */ if (peer) { objPtr = Tls_NewX509Obj(interp, peer); - if (objc == 2) { X509_free(peer); } + if (objc == 2) { + X509_free(peer); + peer = NULL; + } } else { objPtr = Tcl_NewListObj(0, NULL); } /* Peer cert chain (client only) */ STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(statePtr->ssl); - if (!peer && (ssl_certs == NULL || sk_X509_num(ssl_certs) == 0)) { + if (ssl_certs == NULL || sk_X509_num(ssl_certs) == 0) { Tcl_SetErrorCode(interp, "TLS", "STATUS", "CERTIFICATE", (char *) NULL); + Tcl_IncrRefCount(objPtr); + Tcl_DecrRefCount(objPtr); return TCL_ERROR; } - /* Peer name from cert */ + /* Peer name */ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("peername", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get0_peername(statePtr->ssl), -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("sbits", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_get_cipher_bits(statePtr->ssl, NULL))); @@ -2246,13 +2252,13 @@ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_CIPHER_get_name(cipher), -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("standard_name", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_CIPHER_standard_name(cipher), -1)); bits = SSL_CIPHER_get_bits(cipher, &alg_bits); - Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("bits", -1)); + Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("secret_bits", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(bits)); - Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("secret_bits", -1)); + Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("algorithm_bits", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(alg_bits)); /* alg_bits is actual key secret bits. If use bits and secret (algorithm) bits differ, the rest of the bits are fixed, i.e. for limited export ciphers (bits < 56) */ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("min_version", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_CIPHER_get_version(cipher), -1)); Index: generic/tlsX509.c ================================================================== --- generic/tlsX509.c +++ generic/tlsX509.c @@ -69,12 +69,12 @@ Tcl_Obj* Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert) { Tcl_Obj *certPtr = Tcl_NewListObj(0, NULL); BIO *bio; - int nid, pknid, bits, num_of_exts, len; - uint32_t xflags; + int mdnid, pknid, bits, num_of_exts, len; + uint32_t xflags, usage; char subject[BUFSIZ]; char issuer[BUFSIZ]; char serial[BUFSIZ]; char notBefore[BUFSIZ]; char notAfter[BUFSIZ]; @@ -164,157 +164,15 @@ } BIO_free(bio); } - /* Version of the encoded certificate */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("version", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewLongObj(X509_get_version(cert)+1)); - - /* Signature algorithm used by the CA to sign the certificate. Must match signatureAlgorithm. */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signature", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(X509_get_signature_nid(cert)),-1)); - - /* SHA1 Fingerprint of cert - DER representation */ - X509_digest(cert, EVP_sha1(), md, &len); - len = String_to_Hex(md, len, buffer, BUFSIZ); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha1_hash", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); - - /* SHA256 Fingerprint of cert - DER representation */ - X509_digest(cert, EVP_sha256(), md, &len); - len = String_to_Hex(md, len, buffer, BUFSIZ); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha256_hash", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); - - /* The subject identifies the entity associated with the public key stored in the subject public key field. */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subject", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(subject, -1)); - - /* The issuer identifies the entity that has signed and issued the certificate. */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("issuer", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(issuer, -1)); - - /* Certificate validity period is the time interval during which the CA - warrants that it will maintain information about the status of the certificate. */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("notBefore", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(notBefore, -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("notAfter", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(notAfter, -1)); - - /* Unique number assigned by CA to certificate. */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("serialNumber", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(serial, -1)); - + /* The certificate data */ Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("certificate", -1)); Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(certStr, -1)); - /* Information about the signature of certificate cert */ - /* Contains the public key and identify the algorithm with which the key is used */ - if (X509_get_signature_info(cert, &nid, &pknid, &bits, &xflags) == 1) { - ASN1_BIT_STRING *key; - - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signingDigest", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(nid),-1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKeyAlgorithm", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(pknid),-1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("bits", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(bits)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extension_flags", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(xflags)); - - /* Public key - X509_get0_pubkey */ - key = X509_get0_pubkey_bitstr(cert); - len = String_to_Hex(key->data, key->length, buffer, BUFSIZ); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKey", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); - - /* Check if cert was issued by CA cert issuer or self signed */ - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("self_signed", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewBooleanObj(X509_check_issued(cert, cert) == X509_V_OK)); - } - - /* Unique Ids - The unique identifiers are present in the certificate to handle the - possibility of reuse of subject and/or issuer names over time.*/ - { - const ASN1_BIT_STRING *iuid, *suid; - X509_get0_uids(cert, &iuid, &suid); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("issuerUniqueId", -1)); - if (iuid != NULL) { - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewByteArrayObj((char *)iuid->data, iuid->length)); - } else { - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); - } - - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectUniqueId", -1)); - if (suid != NULL) { - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewByteArrayObj((char *)suid->data, suid->length)); - } else { - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); - } - } - - /* Count of extensions */ - num_of_exts = X509_get_ext_count(cert); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("num_extensions", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(num_of_exts)); - - /* Get extension names */ - if (num_of_exts > 0) { - Tcl_Obj *extsPtr = Tcl_NewListObj(0, NULL); - const STACK_OF(X509_EXTENSION) *exts; - exts = X509_get0_extensions(cert); - - for (int i=0; i < num_of_exts; i++) { - X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); - ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); - unsigned nid2 = OBJ_obj2nid(obj); - Tcl_ListObjAppendElement(interp, extsPtr, Tcl_NewStringObj(OBJ_nid2ln(nid2), -1)); - } - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extensions", -1)); - Tcl_ListObjAppendElement(interp, certPtr, extsPtr); - } - - /* Certificate Alias as UTF-8 string */ - { - unsigned char *bstring; - len = 0; - bstring = X509_alias_get0(cert, &len); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("alias", -1)); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj((char *)bstring, len)); - } - - /* Get Subject Key id, Authority Key id. The Authority Key Identifier (AKI) of a - certificate should be the Subject Key Identifier (SKI) of its signer (the CA). */ - { - /* Identifies certificates that contain a particular public key */ - ASN1_OCTET_STRING *astring; - /* X509_keyid_get0 */ - astring = X509_get0_subject_key_id(cert); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectKeyIdentifier", -1)); - if (astring != NULL) { - len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); - } else { - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); - } - - /* Identifies the public key corresponding to the private key used to sign a certificate */ - astring = X509_get0_authority_key_id(cert); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("authorityKeyIdentifier", -1)); - if (astring != NULL) { - len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ); - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); - } else { - Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); - } - - /* const GENERAL_NAMES *X509_get0_authority_issuer(cert); - const ASN1_INTEGER *X509_get0_authority_serial(cert); */ - } - - /* Signature algorithm and value */ + /* Signature algorithm and value - RFC 5280 section 4.1.1.2 and 4.1.1.3 */ /* The signatureAlgorithm field contains the identifier for the cryptographic algorithm used by the CA to sign this certificate. The signatureValue field contains a digital signature computed upon the ASN.1 DER encoded tbsCertificate. */ { const X509_ALGOR *sig_alg; @@ -334,36 +192,260 @@ Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); } else { Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); } } + + /* Version of the encoded certificate - RFC 5280 section 4.1.2.1 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("version", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewLongObj(X509_get_version(cert)+1)); + + /* Unique number assigned by CA to certificate - RFC 5280 section 4.1.2.2 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("serialNumber", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(serial, -1)); + + /* Signature algorithm used by the CA to sign the certificate. Must match + signatureAlgorithm. RFC 5280 section 4.1.2.3 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signature", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(X509_get_signature_nid(cert)),-1)); + + /* The issuer identifies the entity that has signed and issued the certificate. + RFC 5280 section 4.1.2.4 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("issuer", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(issuer, -1)); + + /* Certificate validity period is the time interval during which the CA + warrants that it will maintain information about the status of the certificate. + RFC 5280 section 4.1.2.5 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("notBefore", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(notBefore, -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("notAfter", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(notAfter, -1)); + + /* The subject identifies the entity associated with the public key stored + in the subject public key field. RFC 5280 section 4.1.2.6 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subject", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(subject, -1)); + + /* SHA1 Fingerprint of cert - DER representation */ + X509_digest(cert, EVP_sha1(), md, &len); + len = String_to_Hex(md, len, buffer, BUFSIZ); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha1_hash", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); + + /* SHA256 Fingerprint of cert - DER representation */ + X509_digest(cert, EVP_sha256(), md, &len); + len = String_to_Hex(md, len, buffer, BUFSIZ); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha256_hash", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); + + /* Subject Public Key Info specifies the public key and identifies the + algorithm with which the key is used. RFC 5280 section 4.1.2.7 */ + if (X509_get_signature_info(cert, &mdnid, &pknid, &bits, &xflags) == 1) { + ASN1_BIT_STRING *key; + unsigned int n; + + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signingDigest", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(mdnid),-1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKeyAlgorithm", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(pknid),-1)); + /* Effective security bits */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("bits", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(bits)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extension_flags", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(xflags)); + + key = X509_get0_pubkey_bitstr(cert); + len = String_to_Hex(key->data, key->length, buffer, BUFSIZ); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKey", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); + + /* Check if cert was issued by CA cert issuer or self signed */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("self_signed", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewBooleanObj(X509_check_issued(cert, cert) == X509_V_OK)); + + if (X509_digest(cert, EVP_get_digestbynid(mdnid), md, &n)) { + len = String_to_Hex(md, (int)n, buffer, BUFSIZ); + } else { + len = 0; + } + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signatureHash", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); + } + + /* Check if cert was issued by CA cert issuer or self signed */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("selfIssued", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewBooleanObj(xflags & EXFLAG_SI)); + + /* Check if cert was issued by CA cert issuer or self signed */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("selfSigned", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewBooleanObj(xflags & EXFLAG_SS)); + + + /* Unique Ids - The unique identifiers are present in the certificate to handle the + possibility of reuse of subject and/or issuer names over time. RFC 5280 section 4.1.2.8 */ + { + const ASN1_BIT_STRING *iuid, *suid; + X509_get0_uids(cert, &iuid, &suid); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("issuerUniqueId", -1)); + if (iuid != NULL) { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewByteArrayObj((char *)iuid->data, iuid->length)); + } else { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); + } + + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectUniqueId", -1)); + if (suid != NULL) { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewByteArrayObj((char *)suid->data, suid->length)); + } else { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); + } + } + + /* X509 v3 Extensions - RFC 5280 section 4.1.2.9 */ + num_of_exts = X509_get_ext_count(cert); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("num_extensions", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(num_of_exts)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extensions", -1)); + if (num_of_exts > 0) { + Tcl_Obj *extsPtr = Tcl_NewListObj(0, NULL); + const STACK_OF(X509_EXTENSION) *exts; + exts = X509_get0_extensions(cert); + + for (int i=0; i < num_of_exts; i++) { + X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + unsigned nid2 = OBJ_obj2nid(obj); + Tcl_ListObjAppendElement(interp, extsPtr, Tcl_NewStringObj(OBJ_nid2ln(nid2), -1)); + } + Tcl_ListObjAppendElement(interp, certPtr, extsPtr); + } else { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); + } + + /* Authority Key Identifier (AKI) of a certificate should be the Subject Key + Identifier (SKI) of its signer (the CA). RFC 5280 section 4.2.1.1 */ + { + ASN1_OCTET_STRING *astring = X509_get0_authority_key_id(cert); + if (astring != NULL) { + len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ); + } else { + len = 0; + } + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("authorityKeyIdentifier", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); + } + + /* Subject Key Identifier (SKI) provides a means of identifying certificates + that contain a particular public key. RFC 5280 section 4.2.1.2 */ + { + ASN1_OCTET_STRING *astring = X509_get0_subject_key_id(cert); + if (astring != NULL) { + len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ); + } else { + len = 0; + } + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectKeyIdentifier", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len)); + } /* Key usage extension defines the purpose (e.g., encipherment, signature, certificate - signing) of the key contained in the certificate. */ + signing) of the key contained in the certificate. RFC 5280 section 4.2.1.3 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("keyUsage", -1)); + usage = X509_get_key_usage(cert); + if ((xflags & EXFLAG_KUSAGE) || usage < 0xffff) { + Tcl_Obj *tmpPtr = Tcl_NewListObj(0, NULL); + if (usage & KU_DIGITAL_SIGNATURE) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Digital Signature", -1)); + } + if (usage & KU_NON_REPUDIATION) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Non-Repudiation", -1)); + } + if (usage & KU_KEY_ENCIPHERMENT) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Key Encipherment", -1)); + } + if (usage & KU_DATA_ENCIPHERMENT) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Data Encipherment", -1)); + } + if (usage & KU_KEY_AGREEMENT) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Key Agreement", -1)); + } + if (usage & KU_KEY_CERT_SIGN) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Certificate Signing", -1)); + } + if (usage & KU_CRL_SIGN) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("CRL Signing", -1)); + } + if (usage & KU_ENCIPHER_ONLY) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Encipher Only", -1)); + } + if (usage & KU_DECIPHER_ONLY) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Decipher Only", -1)); + } + Tcl_ListObjAppendElement(interp, certPtr, tmpPtr); + } else { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1)); + } + + + /* Purpose */ + { + char *purpose = NULL; + + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("purpose", -1)); + if (X509_check_purpose(cert, X509_PURPOSE_SSL_CLIENT, 0) > 0) { + purpose = "SSL Client"; + } else if (X509_check_purpose(cert, X509_PURPOSE_SSL_SERVER, 0) > 0) { + purpose = "SSL Server"; + } else if (X509_check_purpose(cert, X509_PURPOSE_NS_SSL_SERVER, 0) > 0) { + purpose = "MSS SSL Server"; + } else if (X509_check_purpose(cert, X509_PURPOSE_SMIME_SIGN, 0) > 0) { + purpose = "SMIME Signing"; + } else if (X509_check_purpose(cert, X509_PURPOSE_SMIME_ENCRYPT, 0) > 0) { + purpose = "SMIME Encryption"; + } else if (X509_check_purpose(cert, X509_PURPOSE_CRL_SIGN, 0) > 0) { + purpose = "CRL Signing"; + } else if (X509_check_purpose(cert, X509_PURPOSE_ANY, 0) > 0) { + purpose = "Any"; + } else if (X509_check_purpose(cert, X509_PURPOSE_OCSP_HELPER, 0) > 0) { + purpose = "OCSP Helper"; + } else if (X509_check_purpose(cert, X509_PURPOSE_TIMESTAMP_SIGN, 0) > 0) { + purpose = "Timestamp Signing"; + } else { + purpose = ""; + } + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(purpose, -1)); + } + { Tcl_Obj *purpPtr = Tcl_NewListObj(0, NULL); for (int j = 0; j < X509_PURPOSE_get_count(); j++) { X509_PURPOSE *ptmp = X509_PURPOSE_get0(j); Tcl_Obj *tmpPtr = Tcl_NewListObj(0, NULL); for (int i = 0; i < 2; i++) { int idret = X509_check_purpose(cert, X509_PURPOSE_get_id(ptmp), i); Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj(i ? "CA" : "nonCA", -1)); - Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj(idret ? "Yes" : "No", -1)); + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj(idret == 1 ? "Yes" : "No", -1)); } Tcl_ListObjAppendElement(interp, purpPtr, Tcl_NewStringObj(X509_PURPOSE_get0_name(ptmp), -1)); Tcl_ListObjAppendElement(interp, purpPtr, tmpPtr); } Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("certificatePurpose", -1)); Tcl_ListObjAppendElement(interp, certPtr, purpPtr); } /* Certificate Policies - indicates the issuing CA considers its issuerDomainPolicy - equivalent to the subject CA's subjectDomainPolicy. */ + equivalent to the subject CA's subjectDomainPolicy. RFC 5280 section 4.2.1.4 */ + if (xflags & EXFLAG_INVALID_POLICY) { + /* Reject cert */ + } + + /* Policy Mappings - RFC 5280 section 4.2.1.5 */ - /* Subject Alternative Name (SAN) extension. Additional URLs, DNS name, or IP addresses - bound to certificate. */ + /* Subject Alternative Name (SAN) contains additional URLs, DNS name, or IP + addresses bound to certificate. RFC 5280 section 4.2.1.6 */ san = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (san) { Tcl_Obj *namesPtr = Tcl_NewListObj(0, NULL); bio = BIO_new(BIO_s_mem()); @@ -383,11 +465,12 @@ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free); Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectAltName", -1)); Tcl_ListObjAppendElement(interp, certPtr, namesPtr); } - /* Issuer Alternative Name */ + /* Issuer Alternative Name (issuerAltName) is used to associate Internet + style identities with the certificate issuer. RFC 5280 section 4.2.1.7 */ san = X509_get_ext_d2i(cert, NID_issuer_alt_name, NULL, NULL); if (san) { Tcl_Obj *namesPtr = Tcl_NewListObj(0, NULL); bio = BIO_new(BIO_s_mem()); @@ -407,12 +490,67 @@ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free); Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("issuerAltName", -1)); Tcl_ListObjAppendElement(interp, certPtr, namesPtr); } - /* Get the STACK of all crl distribution point entries for this certificate. */ - /* CRL_DIST_POINTS is typedef on STACK_OF(DIST_POINT). */ + /* Subject Directory Attributes provides identification attributes (e.g., nationality) + of the subject. RFC 5280 section 4.2.1.8 (subjectDirectoryAttributes) */ + + /* Basic Constraints identifies whether the subject of the cert is a CA and + the max depth of valid cert paths that include this cert. + RFC 5280 section 4.2.1.9 (basicConstraints, NID_basic_constraints) */ + if (xflags & EXFLAG_BCONS || xflags & EXFLAG_CA) { + } + + /* Name Constraints is only used in CA certs to indicate a name space within + which all subject names in subsequent certificates in a certification path + MUST be located. RFC 5280 section 4.2.1.10 */ + + /* Policy Constraints is only used in CA certs to limit the length of a + cert chain that may be issued from that CA. RFC 5280 section 4.2.1.11 */ + + /* Extended Key Usage indicates one or more purposes for which the certified + public key may be used, in addition to or in place of the basic purposes. + RFC 5280 section 4.2.1.12 */ + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extendedKeyUsage", -1)); + usage = X509_get_extended_key_usage(cert); + if ((xflags & EXFLAG_XKUSAGE) || usage < 0xffff) { + Tcl_Obj *tmpPtr = Tcl_NewListObj(0, NULL); + if (usage & XKU_SSL_SERVER) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("TLS Web Server Authentication", -1)); + } + if (usage & XKU_SSL_CLIENT) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("TLS Web Client Authentication", -1)); + } + if (usage & XKU_SMIME) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("E-mail Protection", -1)); + } + if (usage & XKU_CODE_SIGN) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Code Signing", -1)); + } + if (usage & XKU_SGC) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("SGC", -1)); + } + if (usage & XKU_OCSP_SIGN) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("OCSP Signing", -1)); + } + if (usage & XKU_TIMESTAMP) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Time Stamping", -1)); + } + if (usage & XKU_DVCS ) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("DVCS", -1)); + } + if (usage & XKU_ANYEKU) { + Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj("Any Extended Key Usage", -1)); + } + Tcl_ListObjAppendElement(interp, certPtr, tmpPtr); + } else { + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj((int)X509_get_extended_key_usage(cert))); + } + + /* CRL Distribution Points extension identifies how CRL information is + obtained. RFC 5280 section 4.2.1.13*/ crl = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL); if (crl) { Tcl_Obj *namesPtr = Tcl_NewListObj(0, NULL); for (int i=0; i < sk_DIST_POINT_num(crl); i++) { @@ -443,14 +581,13 @@ CRL_DIST_POINTS_free(crl); Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("crlDistributionPoints", -1)); Tcl_ListObjAppendElement(interp, certPtr, namesPtr); } - /* Subject Directory Attributes */ - - /* Basic Constraints - identifies whether the subject of the certificate is a CA and - the maximum depth of valid certification paths that include this certificate. */ + /* Freshest CRL extension */ + if (xflags & EXFLAG_FRESHEST) { + } /* Get OSCP URL */ ocsp = X509_get1_ocsp(cert); if (ocsp) { Tcl_Obj *urlsPtr = Tcl_NewListObj(0, NULL); @@ -462,8 +599,17 @@ X509_email_free(ocsp); Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("ocsp", -1)); Tcl_ListObjAppendElement(interp, certPtr, urlsPtr); } + + /* Certificate Alias as UTF-8 string */ + { + unsigned char *bstring; + len = 0; + bstring = X509_alias_get0(cert, &len); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("alias", -1)); + Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj((char *)bstring, len)); + } return certPtr; }