Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -368,11 +368,11 @@ } } else if (cert == NULL || ssl == NULL) { return 0; } - dprintf("VerifyCallback: eval callback"); + dprintf("VerifyCallback: create callback command"); /* Create command to eval with fn, chan, depth, cert info list, status, and error args */ cmdPtr = Tcl_DuplicateObj(statePtr->vcmd); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("verify", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, @@ -383,10 +383,12 @@ Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj((char*)X509_verify_cert_error_string(err), -1)); /* Prevent I/O while callback is in progress */ /* statePtr->flags |= TLS_TCL_CALLBACK; */ + + dprintf("VerifyCallback: eval callback"); /* Eval callback command */ Tcl_IncrRefCount(cmdPtr); ok = EvalCallback(interp, statePtr, cmdPtr); Tcl_DecrRefCount(cmdPtr); @@ -420,10 +422,12 @@ dprintf("Called with message %s", msg); if (statePtr->callback == (Tcl_Obj*)NULL) { return; } + + dprintf("Tls_Error: create callback command"); /* Create command to eval with fn, chan, and message args */ cmdPtr = Tcl_DuplicateObj(statePtr->callback); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("error", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, @@ -439,10 +443,12 @@ while ((err = ERR_get_error()) != 0) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(ERR_reason_error_string(err), -1)); } Tcl_ListObjAppendElement(interp, cmdPtr, listPtr); } + + dprintf("Tls_Error: eval callback"); /* Eval callback command */ Tcl_IncrRefCount(cmdPtr); EvalCallback(interp, statePtr, cmdPtr); Tcl_DecrRefCount(cmdPtr); @@ -515,16 +521,20 @@ return (int) len; } else { return -1; } } + + dprintf("PasswordCallback: create callback command"); /* Create command to eval with fn, rwflag, and size args */ cmdPtr = Tcl_DuplicateObj(statePtr->password); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("password", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(rwflag)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(size)); + + dprintf("PasswordCallback: eval callback"); Tcl_Preserve((ClientData) interp); Tcl_Preserve((ClientData) statePtr); /* Eval callback command */ @@ -2278,10 +2288,12 @@ const SSL_CIPHER *cipher; const SSL_SESSION *session; const EVP_MD *md; (void) clientData; + dprintf("Called"); + if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channel"); return TCL_ERROR; } @@ -2346,14 +2358,14 @@ /* Is TLS */ LAPPEND_BOOL(interp, objPtr, "is_tls", SSL_is_tls(ssl)); #endif /* DANE TLS authentication */ - LAPPEND_BOOL(interp, objPtr, "dane_auth", SSL_get0_dane(ssl) != NULL); + LAPPEND_BOOL(interp, objPtr, "dane_auth", SSL_get0_dane((SSL *)ssl) != NULL); /* Waiting for async */ - LAPPEND_BOOL(interp, objPtr, "waiting_for_async", SSL_waiting_for_async(ssl)); + LAPPEND_BOOL(interp, objPtr, "waiting_for_async", SSL_waiting_for_async((SSL *)ssl)); /* Time-out */ LAPPEND_LONG(interp, objPtr, "time-out", SSL_get_default_timeout(ssl)); /* Is Certificate Transparency validation enabled */ @@ -2971,13 +2983,14 @@ * Side effects: * Shutdown SSL library * *------------------------------------------------------* */ -static int TlsLibShutdown(ClientData clientData) { +void TlsLibShutdown(ClientData clientData) { + dprintf("Called"); + BIO_cleanup(); - return TCL_OK; } /* *------------------------------------------------------* * Index: generic/tlsInt.h ================================================================== --- generic/tlsInt.h +++ generic/tlsInt.h @@ -138,13 +138,13 @@ } #define LAPPEND_BOOL(interp, obj, text, value) {\ if (text != NULL) Tcl_ListObjAppendElement(interp, obj, Tcl_NewStringObj(text, -1)); \ Tcl_ListObjAppendElement(interp, obj, Tcl_NewBooleanObj(value)); \ } -#define LAPPEND_OBJ(interp, obj, text, listObj) {\ +#define LAPPEND_OBJ(interp, obj, text, tclObj) {\ if (text != NULL) Tcl_ListObjAppendElement(interp, obj, Tcl_NewStringObj(text, -1)); \ - Tcl_ListObjAppendElement(interp, obj, listObj); \ + Tcl_ListObjAppendElement(interp, obj, (tclObj != NULL) ? tclObj : Tcl_NewStringObj("", 0)); \ } /* * OpenSSL BIO Routines */ Index: generic/tlsX509.c ================================================================== --- generic/tlsX509.c +++ generic/tlsX509.c @@ -14,36 +14,40 @@ #include #include #include "tlsInt.h" /* Define maximum certificate size. Max PEM size 100kB and DER size is 24kB. */ -#define CERT_STR_SIZE 32768 +#define CERT_STR_SIZE 24576 /* * String_to_Hex -- * Format contents of a binary string as a hex string * * Results: - * Returns size of output hex string + * TCL byte array object with x509 identifier as a hex string * * Side Effects: * None * */ -Tcl_Size String_to_Hex(unsigned char* input, int ilen, unsigned char *buffer, Tcl_Size blen) { - Tcl_Size len = 0; +Tcl_Obj *String_to_Hex(unsigned char* input, int ilen) { unsigned char *iptr = input; - unsigned char *optr = &buffer[0]; + Tcl_Obj *resultObj = Tcl_NewByteArrayObj(NULL, 0); + unsigned char *data = Tcl_SetByteArrayLength(resultObj, ilen*2); + unsigned char *dptr = &data[0]; const char *hex = "0123456789abcdef"; - for (int i = 0; i < ilen && len < blen - 1; i++, len += 2) { - *optr++ = hex[(*iptr>>4)&0xF]; - *optr++ = hex[(*iptr++)&0xF]; + if (resultObj == NULL) { + return NULL; + } + + for (int i = 0; i < ilen; i++) { + *dptr++ = hex[(*iptr>>4)&0xF]; + *dptr++ = hex[(*iptr++)&0xF]; } - *optr = 0; - return len; + return resultObj; } /* * BIO_to_Buffer -- * Output contents of a BIO to a buffer @@ -53,16 +57,16 @@ * * Side effects: * None * */ -Tcl_Size BIO_to_Buffer(int result, BIO *bio, void *buffer, int blen) { +Tcl_Size BIO_to_Buffer(int result, BIO *bio, void *output, int olen) { Tcl_Size len = 0; int pending = BIO_pending(bio); if (result) { - len = (Tcl_Size) BIO_read(bio, buffer, (pending < blen) ? pending : blen); + len = (Tcl_Size) BIO_read(bio, output, (pending < olen) ? pending : olen); (void)BIO_flush(bio); if (len < 0) { len = 0; } } @@ -103,26 +107,23 @@ /* * Tls_x509Identifier -- * Get X.509 certificate Authority or Subject Key Identifiers * * Results: - * TCL string object with x509 identifier as a hex string + * TCL byte array object with x509 identifier as a hex string * * Side effects: * None * */ Tcl_Obj *Tls_x509Identifier(const ASN1_OCTET_STRING *astring) { Tcl_Obj *resultObj = NULL; - Tcl_Size len = 0; - unsigned char buffer[1024]; if (astring != NULL) { - len = String_to_Hex((unsigned char *)ASN1_STRING_get0_data(astring), - ASN1_STRING_length(astring), buffer, 1024); + resultObj = String_to_Hex((unsigned char *)ASN1_STRING_get0_data(astring), + ASN1_STRING_length(astring)); } - resultObj = Tcl_NewStringObj((char *) &buffer[0], len); return resultObj; } /* * Tls_x509KeyUsage -- @@ -461,27 +462,28 @@ * * Side effects: * None * */ - -Tcl_Obj* -Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert, int all) { +Tcl_Obj *Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert, int all) { Tcl_Obj *resultObj = Tcl_NewListObj(0, NULL); BIO *bio = BIO_new(BIO_s_mem()); int mdnid, pknid, bits; Tcl_Size len; unsigned int ulen; uint32_t xflags; - char buffer[BUFSIZ]; - unsigned char md[EVP_MAX_MD_SIZE]; unsigned long flags = XN_FLAG_RFC2253 | ASN1_STRFLGS_UTF8_CONVERT; flags &= ~ASN1_STRFLGS_ESC_MSB; - if (interp == NULL || cert == NULL || bio == NULL || resultObj == NULL) { + char *buffer = ckalloc(BUFSIZ > EVP_MAX_MD_SIZE ? BUFSIZ : EVP_MAX_MD_SIZE); + + printf("Called\n"); + + if (interp == NULL || cert == NULL || bio == NULL || resultObj == NULL || buffer == NULL) { Tcl_DecrRefCount(resultObj); BIO_free(bio); + if (buffer != NULL) ckfree(buffer); return NULL; } /* Signature algorithm and value - RFC 5280 section 4.1.1.2 and 4.1.1.3 */ /* signatureAlgorithm is the id of the cryptographic algorithm used by the @@ -494,12 +496,15 @@ X509_get0_signature(&sig, &sig_alg, cert); /* sig_nid = X509_get_signature_nid(cert) */ sig_nid = OBJ_obj2nid(sig_alg->algorithm); LAPPEND_STR(interp, resultObj, "signatureAlgorithm", OBJ_nid2ln(sig_nid), -1); - len = (sig_nid != NID_undef) ? String_to_Hex(sig->data, sig->length, (unsigned char *) buffer, BUFSIZ) : 0; - LAPPEND_STR(interp, resultObj, "signatureValue", buffer, len); + if (sig_nid != NID_undef) { + LAPPEND_OBJ(interp, resultObj, "signatureValue", String_to_Hex(sig->data, sig->length)); + } else { + LAPPEND_STR(interp, resultObj, "signatureValue", "", 0); + } } /* Version of the encoded certificate - RFC 5280 section 4.1.2.1 */ LAPPEND_LONG(interp, resultObj, "version", X509_get_version(cert)+1); @@ -529,19 +534,17 @@ the subject public key field. RFC 5280 section 4.1.2.6 */ len = BIO_to_Buffer(X509_NAME_print_ex(bio, X509_get_subject_name(cert), 0, flags), bio, buffer, BUFSIZ); LAPPEND_STR(interp, resultObj, "subject", buffer, len); /* SHA1 Digest (Fingerprint) of cert - DER representation */ - if (X509_digest(cert, EVP_sha1(), md, &ulen)) { - len = String_to_Hex(md, (int) ulen, (unsigned char *) buffer, BUFSIZ); - LAPPEND_STR(interp, resultObj, "sha1_hash", buffer, len); + if (X509_digest(cert, EVP_sha1(), (unsigned char *)buffer, &ulen)) { + LAPPEND_OBJ(interp, resultObj, "sha1_hash", String_to_Hex((unsigned char *)buffer, (int) ulen)); } /* SHA256 Digest (Fingerprint) of cert - DER representation */ - if (X509_digest(cert, EVP_sha256(), md, &ulen)) { - len = String_to_Hex(md, (int) ulen, (unsigned char *) buffer, BUFSIZ); - LAPPEND_STR(interp, resultObj, "sha256_hash", buffer, len); + if (X509_digest(cert, EVP_sha256(), (unsigned char *)buffer, &ulen)) { + LAPPEND_OBJ(interp, resultObj, "sha256_hash", String_to_Hex((unsigned char *)buffer, (int) ulen)); } /* 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)) { @@ -551,25 +554,24 @@ LAPPEND_STR(interp, resultObj, "signingDigest", OBJ_nid2ln(mdnid), -1); LAPPEND_STR(interp, resultObj, "publicKeyAlgorithm", OBJ_nid2ln(pknid), -1); LAPPEND_INT(interp, resultObj, "bits", bits); /* Effective security bits */ key = X509_get0_pubkey_bitstr(cert); - len = String_to_Hex(key->data, key->length, (unsigned char *) buffer, BUFSIZ); - LAPPEND_STR(interp, resultObj, "publicKey", buffer, len); - - len = 0; - if (X509_pubkey_digest(cert, EVP_get_digestbynid(pknid), md, &n)) { - len = String_to_Hex(md, (int) n, (unsigned char *) buffer, BUFSIZ); - } - LAPPEND_STR(interp, resultObj, "publicKeyHash", buffer, len); + LAPPEND_OBJ(interp, resultObj, "publicKey", String_to_Hex(key->data, key->length)); + + if (X509_pubkey_digest(cert, EVP_get_digestbynid(pknid), (unsigned char *)buffer, &n)) { + LAPPEND_OBJ(interp, resultObj, "publicKeyHash", String_to_Hex((unsigned char *)buffer, (int) n)); + } else { + LAPPEND_STR(interp, resultObj, "publicKeyHash", "", 0); + } /* digest of the DER representation of the certificate */ - len = 0; - if (X509_digest(cert, EVP_get_digestbynid(mdnid), md, &n)) { - len = String_to_Hex(md, (int) n, (unsigned char *) buffer, BUFSIZ); + if (X509_digest(cert, EVP_get_digestbynid(mdnid), (unsigned char *)buffer, &n)) { + LAPPEND_OBJ(interp, resultObj, "signatureHash", String_to_Hex((unsigned char *)buffer, (int) n)); + } else { + LAPPEND_STR(interp, resultObj, "signatureHash", "", 0); } - LAPPEND_STR(interp, resultObj, "signatureHash", buffer, len); } /* Certificate Purpose. Call before checking for extensions. */ LAPPEND_STR(interp, resultObj, "purpose", Tls_x509Purpose(cert), -1); LAPPEND_OBJ(interp, resultObj, "certificatePurpose", Tls_x509Purposes(interp, cert)); @@ -699,10 +701,11 @@ unsigned char *allStr, *certStr; if (allObj == NULL || certObj == NULL) { Tcl_DecrRefCount(allObj); BIO_free(bio); + ckfree(buffer); return resultObj; } /* Get certificate */ certStr = Tcl_SetByteArrayLength(certObj, CERT_STR_SIZE); @@ -716,7 +719,8 @@ Tcl_SetByteArrayLength(allObj, len); LAPPEND_OBJ(interp, resultObj, "all", allObj) } BIO_free(bio); + ckfree(buffer); return resultObj; }