Index: doc/tls.html ================================================================== --- doc/tls.html +++ doc/tls.html @@ -110,19 +110,20 @@
  • Synopsis
  • Description
  • Commands
  • Certificate Validation
  • Callback Options
  • Debug
  • Debug Examples
  • HTTP Package Examples
  • @@ -202,22 +203,22 @@

    Specifies the directory where the Certificate Authority (CA) certificates are stored. The default is platform specific and can be set at compile time. The default location can be overridden by the SSL_CERT_DIR environment variable. See Certificate Validation for more details.

    -cafile filename
    -

    Specifies the file with the Certificate Authority (CA) certificates to use. -The default is "cert.pem", in the OpenSSL directory. The default file can -be overridden by the SSL_CERT_FILE environment variable. See -Certificate Validation for more details.

    +

    Specifies the file with the Certificate Authority (CA) certificates to use in +PEM file format. The default is "cert.pem", in the OpenSSL +directory. The default file can be overridden by the SSL_CERT_FILE environment +variable. See Certificate Validation for more details.

    -castore URI

    Specifies the Uniform Resource Identifier (URI) for the Certificate Authority (CA) store, which may be a single container or a catalog of containers. -Starting with OpenSSL 3.2 on Windows, set to "org.openssl.winstore://" -to use the built-in Windows Certificate Store. This store only supports root -certificate stores. See Certificate Validation for more details.

    +Starting with OpenSSL 3.2 on MS Windows, set to "org.openssl.winstore://" +to use the built-in MS Windows Certificate Store. See +Certificate Validation for more details.

    -certfile filename
    -

    Specifies the name of the file with the certificate in PEM format to use +

    Specifies the name of the file with the certificate to use in PEM format as the local (client or server) certificate. It also contains the public key.

    -cert string

    Specifies the certificate to use as a DER encoded string (X.509 DER).

    -cipher string

    Specifies the list of ciphers to use for TLS 1.2 and earlier connections. @@ -240,11 +241,11 @@ handshake to pass errors, tracing information, and protocol messages. See Callback Options for more info.

    -dhparams filename

    Specifies the Diffie-Hellman (DH) parameters file.

    -keyfile filename
    -

    Specifies the private key file. The default value is to use the file +

    Specifies the private key file. The default is to use the file specified by the -certfile option.

    -key string

    Specifies the private key to use as a DER encoded string (PKCS#1 DER).

    -model channel

    Force this channel to share the same SSL_CTX structure as the @@ -255,19 +256,21 @@ The callback should return a password string. See Callback Options for more info.

    -post_handshake bool

    Allow post-handshake session ticket updates.

    -request bool
    -

    Request a certificate from peer during the SSL handshake. This is needed to do -Certificate Validation. Default is true. +

    Request a certificate from the peer during the SSL handshake. This is needed +to do Certificate Validation. Starting in TclTLS 1.8, the default is +true. See Certificate Validation for more details.

    -require bool
    -

    Require a valid certificate from peer during the SSL handshake. If this is set to -true, then -request must also be set to true and a either -cadir, --cafile, -castore, or a platform default must be provided in order to -validate against. The default is false since not all platforms have -certificates to validate against in a form compatible with OpenSSL. +

    Require a valid certificate from the peer during the SSL handshake. If this is +set to true, then -request must also be set to true and a either +-cadir, -cafile, -castore, or a platform default +must be provided in order to validate against. The default in TclTLS 1.8 and +earlier versions is false since not all platforms have certificates to +validate against in a form compatible with OpenSSL. See Certificate Validation for more details.

    -security_level integer

    Specifies the security level (value from 0 to 5). The security level affects the allowed cipher suite encryption algorithms, supported ECC curves, supported signature algorithms, DH parameter sizes, certificate key sizes @@ -495,64 +498,96 @@

    tls::version

    Returns the OpenSSL version string.

    Certificate Validation

    -

    Summary of command line options

    -

    The following options are used for peer Certificate Validation:

    +

    PKI and Certificates

    +

    Using the Public Key Infrastructure (PKI), each user creates a private key that +only they know about and a public key they can exchange with others for use in +encrypting and decrypting data. The process is the sender encrypts their data +using their private key and the receiver's public key. The data is then sent +to the receiver. In a similar manner, the receiver uses their private key and +the sender's public key to decrypt the data. This provides data integrity, to +ensure the data can't be viewed or altered during transport. See the +-key and -keyfile options for how to specify the private key. +Also see the -password option for how to provide the password.

    +

    In order to provide authentication, i.e. ensuring someone is who they say they +are, the public key and user identification info is stored in a X.509 +certificate and that certificate is authenticated (i.e. signed) by a Certificate +Authority (CA). Users can then exchange these certificates during the TLS +initialization process and check them against the root CA certificates to ensure +they are valid. This is handled by OpenSSL via the -request and +-require options. See the -cadir, -cadir, and +-castore options for how tp specify where to find the CA certificates. +Optionally, in a future release, they can also be checked against the Certificate +Revocation List (CRL) of revoked certificates. Certificates can also be +self-signed, but they are by default not trusted unless you add them to your +certificate store.

    +

    Typically when visiting web sites, only the client needs to check the server's +certificate to ensure it is valid. The server doesn't need to check the client +certificate unless you need to authenticate with them to login, etc. See the +-cert and -certfile options if you need to provide a certificate.

    +
    +

    Summary of command line options

    +

    The following options are used for peer certificate validation:

    -cadir directory

    Specifies the directory where the Certificate Authority (CA) certificates are stored. The default is platform specific, but is usually "/etc/ssl/certs" on Linux/Unix systems. The default location can be overridden by the SSL_CERT_DIR environment variable.

    -cafile filename

    Specifies the file with the Certificate Authority (CA) certificates to use in -PEM file format. The default is "cert.pem", in the OpenSSL directory. On -Linux/Unix systems, this is usually "/etc/ssl/ca-bundle.pem". The default file -can be overridden by the SSL_CERT_FILE environment variable.

    +PEM file format. The default is "cert.pem", in the OpenSSL +directory. On Linux/Unix systems, this is usually "/etc/ssl/ca-bundle.pem". +The default file can be overridden by the SSL_CERT_FILE environment +variable.

    -castore URI

    Specifies the Uniform Resource Identifier (URI) for the Certificate Authority (CA) store, which may be a single container or a catalog of containers. -Starting with OpenSSL 3.2 on Windows, set to "org.openssl.winstore://" -to use the built-in Windows Certificate Store. This store only supports root -certificate stores.

    +Starting with OpenSSL 3.2 on MS Windows, set to "org.openssl.winstore://" +to use the built-in MS Windows Certificate Store. +This store only supports root certificate stores. See +Certificate Validation for more details.

    -request bool
    -

    Request a certificate from peer during the SSL handshake. This is needed to do -Certificate Validation. Default is true. In addition, the -client can manually inspect and accept or reject each certificate using the --validatecommand option.

    +

    Request a certificate from the peer during the SSL handshake. This is needed +to do Certificate Validation. Starting in TclTLS 1.8, the default is +true. In addition, the client can manually inspect and accept or reject +each certificate using the -validatecommand option.

    -require bool
    -

    Require a valid certificate from peer during the SSL handshake. If this is set -to true, then -request must also be set to true and either --cadir, -cafile, -castore, or a platform default must be -provided in order to validate against. The default is false since not -all platforms have certificates to validate against in a form compatible with -OpenSSL. See Certificate Validation for more details.

    +

    Require a valid certificate from the peer during the SSL handshake. If this is +set to true, then -request must also be set to true and a either +-cadir, -cafile, -castore, or a platform default +must be provided in order to validate against. The default in TclTLS 1.8 and +earlier versions is false since not all platforms have certificates to +validate against in a form compatible with OpenSSL.

    -

    When are command line options needed?

    -

    By default, a client TLS connection does NOT validate the server certificate -chain. This limitation is due to the lack of a common cross platform -database of Certificate Authority (CA) provided certificates to validate -against. Many Linux systems natively support OpenSSL and thus have these -certificates installed as part of the OS, but MacOS and Windows do not. In -order to use the -require option, one of the following must be true:

    +

    When are command line options needed?

    +

    In TclTLS 1.8 and earlier versions, certificate validation is +NOT enabled by default. This limitation is due to the lack of a common +cross platform database of Certificate Authority (CA) provided certificates to +validate against. Many Linux systems natively support OpenSSL and thus have +these certificates installed as part of the OS, but MacOS and MS Windows do not. +In order to use the -require option, one of the following +must be true:

      -
    • On Linux and Unix systems with OpenSSL already installed, if the CA -certificates are stored in the standard locations, or if the SSL_CERT_DIR -or SSL_CERT_FILE environment variables are set, then -cadir, --cadir, and -castore aren't needed.

    • +
    • On Linux and Unix systems with OpenSSL already installed or if the CA +certificates are available in PEM format, and if they are stored in the +standard locations, or if the SSL_CERT_DIR or SSL_CERT_FILE +environment variables are set, then -cadir, -cadir, +and -castore aren't needed.

    • If OpenSSL is not installed in the default location, or when using Mac OS -or Windows and OpenSSL is installed, the SSL_CERT_DIR and/or +or MS Windows and OpenSSL is installed, the SSL_CERT_DIR and/or SSL_CERT_FILE environment variables or the one of the -cadir, -cadir, or -castore options must be defined.

    • -
    • On Windows, starting in OpenSSL 3.2, it is now possible to access the -built-in Windows Certificate Store from OpenSSL. This can be achieved by +

    • On MS Windows, starting in OpenSSL 3.2, it is now possible to access the +built-in Windows Certificate Store from OpenSSL. This can utilized by setting the -castore option to "org.openssl.winstore://".

    • -
    • If OpenSSL is not installed, the CA certificates must be downloaded and -installed with the user software. The CURL team makes them available at +

    • If OpenSSL is not installed or the CA certificates are not available in PEM +format, the CA certificates must be downloaded and installed with the user +software. The CURL team makes them available at CA certificates extracted from Mozilla in the "cacert.pem" file. You must then either set the SSL_CERT_DIR and/or SSL_CERT_FILE environment variables or the -cadir or -cafile options to the CA cert file's install location. It is your responsibility to keep this file up to date.

    • @@ -564,11 +599,11 @@ to handle intermediate processing by the OpenSSL library, using the -command, -password, and -validate_command options passed to either of tls::socket or tls::import. Unlike previous versions of TclTLS, only if the callback generates an error, will the bgerror command be invoked with the error information.

      -

      Values for Command Callback

      +

      Values for Command Callback

      The callback for the -command option is invoked at several points during the OpenSSL handshake and during routine operations. See below for the possible arguments passed to the callback script. Values returned from the callback are ignored.

      @@ -629,11 +664,11 @@
      verify channelId depth cert status error

      This callback was moved to -validatecommand in TclTLS 1.8.

      -

      Values for Password Callback

      +

      Values for Password Callback

      The callback for the -password option is invoked by TclTLS whenever OpenSSL needs to obtain a password. See below for the possible arguments passed to the callback script. The user provided password is expected to be returned by the callback.

      @@ -648,11 +683,11 @@

      The size is the maximum length of the password in bytes. This argument is new for TclTLS 1.8.

      -

      Values for Validate Command Callback

      +

      Values for Validate Command Callback

      The callback for the -validatecommand option is invoked during the handshake process in order for the application to validate the provided value(s). See below for the possible arguments passed to the callback script. If not specified, OpenSSL will accept all valid certificates and extensions. To reject the value and abort the connection, the callback should return 0. To accept the Index: doc/tls.man ================================================================== --- doc/tls.man +++ doc/tls.man @@ -80,24 +80,24 @@ stored. The default is platform specific and can be set at compile time. The default location can be overridden by the [var SSL_CERT_DIR] environment variable. See [sectref "Certificate Validation"] for more details. [opt_def -cafile [arg filename]] -Specifies the file with the Certificate Authority (CA) certificates to use. -The default is [file cert.pem], in the OpenSSL directory. The default file can -be overridden by the [var SSL_CERT_FILE] environment variable. See -[sectref "Certificate Validation"] for more details. +Specifies the file with the Certificate Authority (CA) certificates to use in +[const PEM] file format. The default is [file cert.pem], in the OpenSSL +directory. The default file can be overridden by the [var SSL_CERT_FILE] environment +variable. See [sectref "Certificate Validation"] for more details. [opt_def -castore [arg URI]] Specifies the Uniform Resource Identifier (URI) for the Certificate Authority (CA) store, which may be a single container or a catalog of containers. -Starting with OpenSSL 3.2 on Windows, set to "[const "org.openssl.winstore://"]" -to use the built-in Windows Certificate Store. This store only supports root -certificate stores. See [sectref "Certificate Validation"] for more details. +Starting with OpenSSL 3.2 on MS Windows, set to "[const "org.openssl.winstore://"]" +to use the built-in MS Windows Certificate Store. See +[sectref "Certificate Validation"] for more details. [opt_def -certfile [arg filename]] -Specifies the name of the file with the certificate in PEM format to use +Specifies the name of the file with the certificate to use in PEM format as the local (client or server) certificate. It also contains the public key. [opt_def -cert [arg string]] Specifies the certificate to use as a DER encoded string (X.509 DER). @@ -126,11 +126,11 @@ [opt_def -dhparams [arg filename]] Specifies the Diffie-Hellman (DH) parameters file. [opt_def -keyfile [arg filename]] -Specifies the private key file. The default value is to use the file +Specifies the private key file. The default is to use the file specified by the [arg -certfile] option. [opt_def -key [arg string]] Specifies the private key to use as a DER encoded string (PKCS#1 DER). @@ -146,20 +146,22 @@ [opt_def -post_handshake [arg bool]] Allow post-handshake session ticket updates. [opt_def -request [arg bool]] -Request a certificate from peer during the SSL handshake. This is needed to do -Certificate Validation. Default is [const true]. +Request a certificate from the peer during the SSL handshake. This is needed +to do Certificate Validation. Starting in TclTLS 1.8, the default is +[const true]. See [sectref "Certificate Validation"] for more details. [opt_def -require [arg bool]] -Require a valid certificate from peer during the SSL handshake. If this is set to -true, then [option -request] must also be set to true and a either [option -cadir], -[option -cafile], [option -castore], or a platform default must be provided in order to -validate against. The default is [const false] since not all platforms have -certificates to validate against in a form compatible with OpenSSL. +Require a valid certificate from the peer during the SSL handshake. If this is +set to true, then [option -request] must also be set to true and a either +[option -cadir], [option -cafile], [option -castore], or a platform default +must be provided in order to validate against. The default in TclTLS 1.8 and +earlier versions is [const false] since not all platforms have certificates to +validate against in a form compatible with OpenSSL. See [sectref "Certificate Validation"] for more details. [opt_def -security_level [arg integer]] Specifies the security level (value from 0 to 5). The security level affects the allowed cipher suite encryption algorithms, supported ECC curves, @@ -500,14 +502,45 @@ [list_end] [section "Certificate Validation"] + +[subsection "PKI and Certificates"] + +Using the Public Key Infrastructure (PKI), each user creates a private key that +only they know about and a public key they can exchange with others for use in +encrypting and decrypting data. The process is the sender encrypts their data +using their private key and the receiver's public key. The data is then sent +to the receiver. In a similar manner, the receiver uses their private key and +the sender's public key to decrypt the data. This provides data integrity, to +ensure the data can't be viewed or altered during transport. See the +[option -key] and [option -keyfile] options for how to specify the private key. +Also see the [option -password] option for how to provide the password. +[para] +In order to provide authentication, i.e. ensuring someone is who they say they +are, the public key and user identification info is stored in a X.509 +certificate and that certificate is authenticated (i.e. signed) by a Certificate +Authority (CA). Users can then exchange these certificates during the TLS +initialization process and check them against the root CA certificates to ensure +they are valid. This is handled by OpenSSL via the [option -request] and +[option -require] options. See the [option -cadir], [option -cadir], and +[option -castore] options for how tp specify where to find the CA certificates. +Optionally, in a future release, they can also be checked against the Certificate +Revocation List (CRL) of revoked certificates. Certificates can also be +self-signed, but they are by default not trusted unless you add them to your +certificate store. +[para] +Typically when visiting web sites, only the client needs to check the server's +certificate to ensure it is valid. The server doesn't need to check the client +certificate unless you need to authenticate with them to login, etc. See the +[option -cert] and [option -certfile] options if you need to provide a certificate. + [subsection "Summary of command line options"] -The following options are used for peer Certificate Validation: +The following options are used for peer certificate validation: [list_begin options] [opt_def -cadir [arg directory]] Specifies the directory where the Certificate Authority (CA) certificates are @@ -515,68 +548,73 @@ Linux/Unix systems. The default location can be overridden by the [var SSL_CERT_DIR] environment variable. [opt_def -cafile [arg filename]] Specifies the file with the Certificate Authority (CA) certificates to use in -[const PEM] file format. The default is [file cert.pem], in the OpenSSL directory. On -Linux/Unix systems, this is usually [file /etc/ssl/ca-bundle.pem]. The default file -can be overridden by the [var SSL_CERT_FILE] environment variable. +[const PEM] file format. The default is [file cert.pem], in the OpenSSL +directory. On Linux/Unix systems, this is usually [file /etc/ssl/ca-bundle.pem]. +The default file can be overridden by the [var SSL_CERT_FILE] environment +variable. [opt_def -castore [arg URI]] Specifies the Uniform Resource Identifier (URI) for the Certificate Authority (CA) store, which may be a single container or a catalog of containers. -Starting with OpenSSL 3.2 on Windows, set to "[const "org.openssl.winstore://"]" -to use the built-in Windows Certificate Store. This store only supports root -certificate stores. +Starting with OpenSSL 3.2 on MS Windows, set to "[const "org.openssl.winstore://"]" +to use the built-in MS Windows Certificate Store. +This store only supports root certificate stores. See +[sectref "Certificate Validation"] for more details. [opt_def -request [arg bool]] -Request a certificate from peer during the SSL handshake. This is needed to do -Certificate Validation. Default is [const true]. In addition, the -client can manually inspect and accept or reject each certificate using the -[arg -validatecommand] option. +Request a certificate from the peer during the SSL handshake. This is needed +to do Certificate Validation. Starting in TclTLS 1.8, the default is +[const true]. In addition, the client can manually inspect and accept or reject +each certificate using the [arg -validatecommand] option. [opt_def -require [arg bool]] -Require a valid certificate from peer during the SSL handshake. If this is set -to [const true], then [arg -request] must also be set to [const true] and either -[arg -cadir], [arg -cafile], [arg -castore], or a platform default must be -provided in order to validate against. The default is [const false] since not -all platforms have certificates to validate against in a form compatible with -OpenSSL. See [sectref "Certificate Validation"] for more details. +Require a valid certificate from the peer during the SSL handshake. If this is +set to true, then [option -request] must also be set to true and a either +[option -cadir], [option -cafile], [option -castore], or a platform default +must be provided in order to validate against. The default in TclTLS 1.8 and +earlier versions is [const false] since not all platforms have certificates to +validate against in a form compatible with OpenSSL. [list_end] [subsection "When are command line options needed?"] -By default, a client TLS connection does [emph NOT] validate the server certificate -chain. This limitation is due to the lack of a common cross platform -database of Certificate Authority (CA) provided certificates to validate -against. Many Linux systems natively support OpenSSL and thus have these -certificates installed as part of the OS, but MacOS and Windows do not. In -order to use the [option -require] option, one of the following must be true: +In TclTLS 1.8 and earlier versions, certificate validation is +[emph NOT] enabled by default. This limitation is due to the lack of a common +cross platform database of Certificate Authority (CA) provided certificates to +validate against. Many Linux systems natively support OpenSSL and thus have +these certificates installed as part of the OS, but MacOS and MS Windows do not. +In order to use the [option -require] option, one of the following +must be true: [list_begin itemized] [item] -On Linux and Unix systems with OpenSSL already installed, if the CA -certificates are stored in the standard locations, or if the [var SSL_CERT_DIR] -or [var SSL_CERT_FILE] environment variables are set, then [option -cadir], -[option -cadir], and [option -castore] aren't needed. +On Linux and Unix systems with OpenSSL already installed or if the CA +certificates are available in PEM format, and if they are stored in the +standard locations, or if the [var SSL_CERT_DIR] or [var SSL_CERT_FILE] +environment variables are set, then [option -cadir], [option -cadir], +and [option -castore] aren't needed. [item] If OpenSSL is not installed in the default location, or when using Mac OS -or Windows and OpenSSL is installed, the [var SSL_CERT_DIR] and/or +or MS Windows and OpenSSL is installed, the [var SSL_CERT_DIR] and/or [var SSL_CERT_FILE] environment variables or the one of the [option -cadir], [option -cadir], or [option -castore] options must be defined. [item] -On Windows, starting in OpenSSL 3.2, it is now possible to access the -built-in Windows Certificate Store from OpenSSL. This can be achieved by +On MS Windows, starting in OpenSSL 3.2, it is now possible to access the +built-in Windows Certificate Store from OpenSSL. This can utilized by setting the [option -castore] option to "[const org.openssl.winstore://]". [item] -If OpenSSL is not installed, the CA certificates must be downloaded and -installed with the user software. The CURL team makes them available at +If OpenSSL is not installed or the CA certificates are not available in PEM +format, the CA certificates must be downloaded and installed with the user +software. The CURL team makes them available at [uri "https://curl.se/docs/caextract.html" "CA certificates extracted from Mozilla"] in the [file cacert.pem] file. You must then either set the [var SSL_CERT_DIR] and/or [var SSL_CERT_FILE] environment variables or the [option -cadir] or [option -cafile] options to the CA cert file's install location. It is your responsibility to keep this file up to date. Index: doc/tls.n ================================================================== --- doc/tls.n +++ doc/tls.n @@ -357,24 +357,24 @@ stored\&. The default is platform specific and can be set at compile time\&. The default location can be overridden by the \fBSSL_CERT_DIR\fR environment variable\&. See \fBCertificate Validation\fR for more details\&. .TP \fB-cafile\fR \fIfilename\fR -Specifies the file with the Certificate Authority (CA) certificates to use\&. -The default is "\fIcert\&.pem\fR", in the OpenSSL directory\&. The default file can -be overridden by the \fBSSL_CERT_FILE\fR environment variable\&. See -\fBCertificate Validation\fR for more details\&. +Specifies the file with the Certificate Authority (CA) certificates to use in +\fBPEM\fR file format\&. The default is "\fIcert\&.pem\fR", in the OpenSSL +directory\&. The default file can be overridden by the \fBSSL_CERT_FILE\fR environment +variable\&. See \fBCertificate Validation\fR for more details\&. .TP \fB-castore\fR \fIURI\fR Specifies the Uniform Resource Identifier (URI) for the Certificate Authority (CA) store, which may be a single container or a catalog of containers\&. -Starting with OpenSSL 3\&.2 on Windows, set to "\fBorg\&.openssl\&.winstore://\fR" -to use the built-in Windows Certificate Store\&. This store only supports root -certificate stores\&. See \fBCertificate Validation\fR for more details\&. +Starting with OpenSSL 3\&.2 on MS Windows, set to "\fBorg\&.openssl\&.winstore://\fR" +to use the built-in MS Windows Certificate Store\&. See +\fBCertificate Validation\fR for more details\&. .TP \fB-certfile\fR \fIfilename\fR -Specifies the name of the file with the certificate in PEM format to use +Specifies the name of the file with the certificate to use in PEM format as the local (client or server) certificate\&. It also contains the public key\&. .TP \fB-cert\fR \fIstring\fR Specifies the certificate to use as a DER encoded string (X\&.509 DER)\&. .TP @@ -403,11 +403,11 @@ .TP \fB-dhparams\fR \fIfilename\fR Specifies the Diffie-Hellman (DH) parameters file\&. .TP \fB-keyfile\fR \fIfilename\fR -Specifies the private key file\&. The default value is to use the file +Specifies the private key file\&. The default is to use the file specified by the \fI-certfile\fR option\&. .TP \fB-key\fR \fIstring\fR Specifies the private key to use as a DER encoded string (PKCS#1 DER)\&. .TP @@ -423,20 +423,22 @@ .TP \fB-post_handshake\fR \fIbool\fR Allow post-handshake session ticket updates\&. .TP \fB-request\fR \fIbool\fR -Request a certificate from peer during the SSL handshake\&. This is needed to do -Certificate Validation\&. Default is \fBtrue\fR\&. +Request a certificate from the peer during the SSL handshake\&. This is needed +to do Certificate Validation\&. Starting in TclTLS 1\&.8, the default is +\fBtrue\fR\&. See \fBCertificate Validation\fR for more details\&. .TP \fB-require\fR \fIbool\fR -Require a valid certificate from peer during the SSL handshake\&. If this is set to -true, then \fB-request\fR must also be set to true and a either \fB-cadir\fR, -\fB-cafile\fR, \fB-castore\fR, or a platform default must be provided in order to -validate against\&. The default is \fBfalse\fR since not all platforms have -certificates to validate against in a form compatible with OpenSSL\&. +Require a valid certificate from the peer during the SSL handshake\&. If this is +set to true, then \fB-request\fR must also be set to true and a either +\fB-cadir\fR, \fB-cafile\fR, \fB-castore\fR, or a platform default +must be provided in order to validate against\&. The default in TclTLS 1\&.8 and +earlier versions is \fBfalse\fR since not all platforms have certificates to +validate against in a form compatible with OpenSSL\&. See \fBCertificate Validation\fR for more details\&. .TP \fB-security_level\fR \fIinteger\fR Specifies the security level (value from 0 to 5)\&. The security level affects the allowed cipher suite encryption algorithms, supported ECC curves, @@ -752,70 +754,103 @@ .TP \fBtls::version\fR Returns the OpenSSL version string\&. .PP .SH "CERTIFICATE VALIDATION" +.SS "PKI AND CERTIFICATES" +Using the Public Key Infrastructure (PKI), each user creates a private key that +only they know about and a public key they can exchange with others for use in +encrypting and decrypting data\&. The process is the sender encrypts their data +using their private key and the receiver's public key\&. The data is then sent +to the receiver\&. In a similar manner, the receiver uses their private key and +the sender's public key to decrypt the data\&. This provides data integrity, to +ensure the data can't be viewed or altered during transport\&. See the +\fB-key\fR and \fB-keyfile\fR options for how to specify the private key\&. +Also see the \fB-password\fR option for how to provide the password\&. +.PP +In order to provide authentication, i\&.e\&. ensuring someone is who they say they +are, the public key and user identification info is stored in a X\&.509 +certificate and that certificate is authenticated (i\&.e\&. signed) by a Certificate +Authority (CA)\&. Users can then exchange these certificates during the TLS +initialization process and check them against the root CA certificates to ensure +they are valid\&. This is handled by OpenSSL via the \fB-request\fR and +\fB-require\fR options\&. See the \fB-cadir\fR, \fB-cadir\fR, and +\fB-castore\fR options for how tp specify where to find the CA certificates\&. +Optionally, in a future release, they can also be checked against the Certificate +Revocation List (CRL) of revoked certificates\&. Certificates can also be +self-signed, but they are by default not trusted unless you add them to your +certificate store\&. +.PP +Typically when visiting web sites, only the client needs to check the server's +certificate to ensure it is valid\&. The server doesn't need to check the client +certificate unless you need to authenticate with them to login, etc\&. See the +\fB-cert\fR and \fB-certfile\fR options if you need to provide a certificate\&. .SS "SUMMARY OF COMMAND LINE OPTIONS" -The following options are used for peer Certificate Validation: +The following options are used for peer certificate validation: .TP \fB-cadir\fR \fIdirectory\fR Specifies the directory where the Certificate Authority (CA) certificates are stored\&. The default is platform specific, but is usually "\fI/etc/ssl/certs\fR" on Linux/Unix systems\&. The default location can be overridden by the \fBSSL_CERT_DIR\fR environment variable\&. .TP \fB-cafile\fR \fIfilename\fR Specifies the file with the Certificate Authority (CA) certificates to use in -\fBPEM\fR file format\&. The default is "\fIcert\&.pem\fR", in the OpenSSL directory\&. On -Linux/Unix systems, this is usually "\fI/etc/ssl/ca-bundle\&.pem\fR"\&. The default file -can be overridden by the \fBSSL_CERT_FILE\fR environment variable\&. +\fBPEM\fR file format\&. The default is "\fIcert\&.pem\fR", in the OpenSSL +directory\&. On Linux/Unix systems, this is usually "\fI/etc/ssl/ca-bundle\&.pem\fR"\&. +The default file can be overridden by the \fBSSL_CERT_FILE\fR environment +variable\&. .TP \fB-castore\fR \fIURI\fR Specifies the Uniform Resource Identifier (URI) for the Certificate Authority (CA) store, which may be a single container or a catalog of containers\&. -Starting with OpenSSL 3\&.2 on Windows, set to "\fBorg\&.openssl\&.winstore://\fR" -to use the built-in Windows Certificate Store\&. This store only supports root -certificate stores\&. +Starting with OpenSSL 3\&.2 on MS Windows, set to "\fBorg\&.openssl\&.winstore://\fR" +to use the built-in MS Windows Certificate Store\&. +This store only supports root certificate stores\&. See +\fBCertificate Validation\fR for more details\&. .TP \fB-request\fR \fIbool\fR -Request a certificate from peer during the SSL handshake\&. This is needed to do -Certificate Validation\&. Default is \fBtrue\fR\&. In addition, the -client can manually inspect and accept or reject each certificate using the -\fI-validatecommand\fR option\&. +Request a certificate from the peer during the SSL handshake\&. This is needed +to do Certificate Validation\&. Starting in TclTLS 1\&.8, the default is +\fBtrue\fR\&. In addition, the client can manually inspect and accept or reject +each certificate using the \fI-validatecommand\fR option\&. .TP \fB-require\fR \fIbool\fR -Require a valid certificate from peer during the SSL handshake\&. If this is set -to \fBtrue\fR, then \fI-request\fR must also be set to \fBtrue\fR and either -\fI-cadir\fR, \fI-cafile\fR, \fI-castore\fR, or a platform default must be -provided in order to validate against\&. The default is \fBfalse\fR since not -all platforms have certificates to validate against in a form compatible with -OpenSSL\&. See \fBCertificate Validation\fR for more details\&. +Require a valid certificate from the peer during the SSL handshake\&. If this is +set to true, then \fB-request\fR must also be set to true and a either +\fB-cadir\fR, \fB-cafile\fR, \fB-castore\fR, or a platform default +must be provided in order to validate against\&. The default in TclTLS 1\&.8 and +earlier versions is \fBfalse\fR since not all platforms have certificates to +validate against in a form compatible with OpenSSL\&. .PP .SS "WHEN ARE COMMAND LINE OPTIONS NEEDED?" -By default, a client TLS connection does \fINOT\fR validate the server certificate -chain\&. This limitation is due to the lack of a common cross platform -database of Certificate Authority (CA) provided certificates to validate -against\&. Many Linux systems natively support OpenSSL and thus have these -certificates installed as part of the OS, but MacOS and Windows do not\&. In -order to use the \fB-require\fR option, one of the following must be true: +In TclTLS 1\&.8 and earlier versions, certificate validation is +\fINOT\fR enabled by default\&. This limitation is due to the lack of a common +cross platform database of Certificate Authority (CA) provided certificates to +validate against\&. Many Linux systems natively support OpenSSL and thus have +these certificates installed as part of the OS, but MacOS and MS Windows do not\&. +In order to use the \fB-require\fR option, one of the following +must be true: .IP \(bu -On Linux and Unix systems with OpenSSL already installed, if the CA -certificates are stored in the standard locations, or if the \fBSSL_CERT_DIR\fR -or \fBSSL_CERT_FILE\fR environment variables are set, then \fB-cadir\fR, -\fB-cadir\fR, and \fB-castore\fR aren't needed\&. +On Linux and Unix systems with OpenSSL already installed or if the CA +certificates are available in PEM format, and if they are stored in the +standard locations, or if the \fBSSL_CERT_DIR\fR or \fBSSL_CERT_FILE\fR +environment variables are set, then \fB-cadir\fR, \fB-cadir\fR, +and \fB-castore\fR aren't needed\&. .IP \(bu If OpenSSL is not installed in the default location, or when using Mac OS -or Windows and OpenSSL is installed, the \fBSSL_CERT_DIR\fR and/or +or MS Windows and OpenSSL is installed, the \fBSSL_CERT_DIR\fR and/or \fBSSL_CERT_FILE\fR environment variables or the one of the \fB-cadir\fR, \fB-cadir\fR, or \fB-castore\fR options must be defined\&. .IP \(bu -On Windows, starting in OpenSSL 3\&.2, it is now possible to access the -built-in Windows Certificate Store from OpenSSL\&. This can be achieved by +On MS Windows, starting in OpenSSL 3\&.2, it is now possible to access the +built-in Windows Certificate Store from OpenSSL\&. This can utilized by setting the \fB-castore\fR option to "\fBorg\&.openssl\&.winstore://\fR"\&. .IP \(bu -If OpenSSL is not installed, the CA certificates must be downloaded and -installed with the user software\&. The CURL team makes them available at +If OpenSSL is not installed or the CA certificates are not available in PEM +format, the CA certificates must be downloaded and installed with the user +software\&. The CURL team makes them available at \fICA certificates extracted from Mozilla\fR [https://curl\&.se/docs/caextract\&.html] in the "\fIcacert\&.pem\fR" file\&. You must then either set the \fBSSL_CERT_DIR\fR and/or \fBSSL_CERT_FILE\fR environment variables or the \fB-cadir\fR or \fB-cafile\fR options to the CA cert file's install location\&. It is your responsibility to keep this file up to date\&. Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -3096,29 +3096,34 @@ if (statePtr->vcmd) { Tcl_DecrRefCount(statePtr->vcmd); statePtr->vcmd = NULL; } + /* Remove list of ALPN protocols */ if (statePtr->protos) { ckfree(statePtr->protos); statePtr->protos = NULL; } + /* BIO_free_all() frees up an entire BIO chain */ if (statePtr->bio) { /* This will call SSL_shutdown. Bug 1414045 */ - dprintf("BIO_free_all(%p)", statePtr->bio); + dprintf("BIO_free(%p)", statePtr->bio); BIO_free_all(statePtr->bio); statePtr->bio = NULL; } + /* Free SSL context and statePtr->p_bio */ if (statePtr->ssl) { - dprintf("SSL_free(%p)", statePtr->ssl); + dprintf("SSL_free(%p) and p_bio(%p)", statePtr->ssl, statePtr->p_bio); SSL_free(statePtr->ssl); statePtr->ssl = NULL; } + /* Free CTX context */ if (statePtr->ctx) { + dprintf("SSL_CTX_free(%p)", statePtr->ctx); SSL_CTX_free(statePtr->ctx); statePtr->ctx = NULL; } dprintf("Returning"); Index: generic/tlsBIO.c ================================================================== --- generic/tlsBIO.c +++ generic/tlsBIO.c @@ -7,15 +7,15 @@ * */ /* tlsBIO.c tlsIO.c - +------+ +-----+ +------+ - | |Tcl_WriteRaw <-- BioWrite| SSL |BIO_write <-- TlsOutputProc <-- Write| | - |socket| | BIO | | App | - | |Tcl_ReadRaw --> BioRead| |BIO_Read --> TlsInputProc --> Read| | - +------+ +-----+ +------+ + +------+ +---+ +---+ + | |Tcl_WriteRaw<--BioOutput|SSL|BIO_write<--TlsOutputProc<--Write| | + |socket| |BIO| |App| + | |Tcl_ReadRaw --> BioInput| |BIO_Read -->TlsInputProc --> Read| | + +------+ +---+ +---+ */ #include "tlsInt.h" #include @@ -59,11 +59,11 @@ } /* *----------------------------------------------------------------------------- * - * BioWrite -- + * BioOutput -- * * This function is used to read encrypted data from the BIO and write it * into the socket. This function will be called in response to the * application calling the BIO_write_ex() or BIO_write() functions. * @@ -75,27 +75,28 @@ * Writes BIO data to channel. * *----------------------------------------------------------------------------- */ -static int BioWrite(BIO *bio, const char *buf, int bufLen) { +static int BioOutput(BIO *bio, const char *buf, int bufLen) { Tcl_Size ret; int is_eof, tclErrno; State *statePtr = (State *) BIO_get_data(bio); Tcl_Channel chan = Tls_GetParent(statePtr, 0); - dprintf("[chan=%p] BioWrite(bio=%p, buf=%p, len=%d)", (void *)chan, (void *) bio, buf, bufLen); + dprintf("[chan=%p] BioOutput(bio=%p, buf=%p, len=%d)", (void *)chan, + (void *) bio, buf, bufLen); BIO_clear_retry_flags(bio); Tcl_SetErrno(0); /* Write data to underlying channel */ ret = Tcl_WriteRaw(chan, buf, (Tcl_Size) bufLen); is_eof = Tcl_Eof(chan); tclErrno = Tcl_GetErrno(); - dprintf("[chan=%p] BioWrite(%d) -> %" TCL_SIZE_MODIFIER "d [tclEof=%d; tclErrno=%d: %s]", + dprintf("[chan=%p] BioOutput(%d) -> %" TCL_SIZE_MODIFIER "d [tclEof=%d; tclErrno=%d: %s]", (void *) chan, bufLen, ret, is_eof, tclErrno, Tcl_ErrnoMsg(tclErrno)); if (ret > 0) { dprintf("Successfully wrote %" TCL_SIZE_MODIFIER "d bytes of data", ret); @@ -123,18 +124,18 @@ } else { dprintf("Unexpected error: %i=%s", tclErrno, Tcl_ErrnoMsg(tclErrno)); } } - dprintf("BioWrite returning %" TCL_SIZE_MODIFIER "d", ret); + dprintf("BioOutput returning %" TCL_SIZE_MODIFIER "d", ret); return (int) ret; } /* *----------------------------------------------------------------------------- * - * BioRead -- + * BioInput -- * * This function is used to read encrypted data from the socket and * write it into the BIO. This function will be called in response to the * application calling the BIO_read_ex() or BIO_read() functions. * @@ -153,17 +154,18 @@ * data is buffered (whether processed or unprocessed) and 0 otherwise. * *----------------------------------------------------------------------------- */ -static int BioRead(BIO *bio, char *buf, int bufLen) { +static int BioInput(BIO *bio, char *buf, int bufLen) { Tcl_Size ret = 0; int is_eof, tclErrno, is_blocked; State *statePtr = (State *) BIO_get_data(bio); Tcl_Channel chan = Tls_GetParent(statePtr, 0); - dprintf("[chan=%p] BioRead(bio=%p, buf=%p, len=%d)", (void *) chan, (void *) bio, buf, bufLen); + dprintf("[chan=%p] BioInput(bio=%p, buf=%p, len=%d)", (void *) chan, + (void *) bio, buf, bufLen); if (buf == NULL || bufLen <= 0) { return 0; } @@ -175,11 +177,11 @@ is_eof = Tcl_Eof(chan); tclErrno = Tcl_GetErrno(); is_blocked = Tcl_InputBlocked(chan); - dprintf("[chan=%p] BioRead(%d) -> %" TCL_SIZE_MODIFIER "d [tclEof=%d; blocked=%d; tclErrno=%d: %s]", + dprintf("[chan=%p] BioInput(%d) -> %" TCL_SIZE_MODIFIER "d [tclEof=%d; blocked=%d; tclErrno=%d: %s]", (void *) chan, bufLen, ret, is_eof, is_blocked, tclErrno, Tcl_ErrnoMsg(tclErrno)); if (ret > 0) { dprintf("Successfully read %" TCL_SIZE_MODIFIER "d bytes of data", ret); @@ -204,11 +206,11 @@ } else { dprintf("Unexpected error: %i=%s", tclErrno, Tcl_ErrnoMsg(tclErrno)); } } - dprintf("BioRead returning %" TCL_SIZE_MODIFIER "d", ret); + dprintf("BioInput returning %" TCL_SIZE_MODIFIER "d", ret); return (int) ret; } /* *----------------------------------------------------------------------------- @@ -229,11 +231,11 @@ */ static int BioPuts(BIO *bio, const char *str) { dprintf("BioPuts(%p) \"%s\"", bio, str); - return BioWrite(bio, str, (int) strlen(str)); + return BioOutput(bio, str, (int) strlen(str)); } /* *----------------------------------------------------------------------------- * @@ -320,11 +322,11 @@ /* opt - Flush any buffered output. Implements BIO_flush. */ dprintf("Got BIO_CTRL_FLUSH"); /* Use Tcl_WriteRaw instead of Tcl_Flush to operate on right chan in stack */ /* Returns 1 for success, <=0 for error/retry. */ ret = ((chan) && (Tcl_WriteRaw(chan, "", 0) >= 0) ? 1 : -1); - /*ret = BioWrite(bio, NULL, 0);*/ + /*ret = BioOutput(bio, NULL, 0);*/ break; case BIO_CTRL_DUP: /* man - extra stuff for 'duped' BIO. Implements BIO_dup_state */ dprintf("Got BIO_CTRL_DUP"); ret = 1; @@ -493,13 +495,13 @@ dprintf("Memory allocation error"); return NULL; } /* Not used BIO_meth_set_write_ex */ - BIO_meth_set_write(BioMethods, BioWrite); + BIO_meth_set_write(BioMethods, BioOutput); /* Not used BIO_meth_set_read_ex */ - BIO_meth_set_read(BioMethods, BioRead); + BIO_meth_set_read(BioMethods, BioInput); BIO_meth_set_puts(BioMethods, BioPuts); BIO_meth_set_ctrl(BioMethods, BioCtrl); BIO_meth_set_create(BioMethods, BioNew); BIO_meth_set_destroy(BioMethods, BioFree); } @@ -510,24 +512,26 @@ return NULL; } #ifdef TCLTLS_SSL_USE_FASTPATH /* - * If the channel can be mapped back to a file descriptor, just use the file descriptor - * with the SSL library since it will likely be optimized for this. + * If the channel can be mapped back to a file descriptor, just use the file + * descriptor with the SSL library since it will likely be optimized for this. */ parentChannel = Tls_GetParent(statePtr, 0); parentChannelType = Tcl_GetChannelType(parentChannel); validParentChannelFd = 0; if (strcmp(parentChannelType->typeName, "tcp") == 0) { void *parentChannelFdIn_p, *parentChannelFdOut_p; int tclGetChannelHandleRet; - tclGetChannelHandleRet = Tcl_GetChannelHandle(parentChannel, TCL_READABLE, &parentChannelFdIn_p); + tclGetChannelHandleRet = Tcl_GetChannelHandle(parentChannel, + TCL_READABLE, &parentChannelFdIn_p); if (tclGetChannelHandleRet == TCL_OK) { - tclGetChannelHandleRet = Tcl_GetChannelHandle(parentChannel, TCL_WRITABLE, &parentChannelFdOut_p); + tclGetChannelHandleRet = Tcl_GetChannelHandle(parentChannel, + TCL_WRITABLE, &parentChannelFdOut_p); if (tclGetChannelHandleRet == TCL_OK) { parentChannelFdIn = PTR2INT(parentChannelFdIn_p); parentChannelFdOut = PTR2INT(parentChannelFdOut_p); if (parentChannelFdIn == parentChannelFdOut) { parentChannelFd = parentChannelFdIn; @@ -536,11 +540,12 @@ } } } if (validParentChannelFd) { - dprintf("We found a shortcut, this channel is backed by a socket: %i", parentChannelFdIn); + dprintf("We found a shortcut, this channel is backed by a socket: %i", + parentChannelFdIn); bio = BIO_new_socket(parentChannelFd, flags); statePtr->flags |= TLS_TCL_FASTPATH; BIO_set_data(bio, statePtr); BIO_set_shutdown(bio, flags); BIO_set_init(bio, 1); Index: generic/tlsIO.c ================================================================== --- generic/tlsIO.c +++ generic/tlsIO.c @@ -16,15 +16,15 @@ * */ /* tlsBIO.c tlsIO.c - +------+ +-----+ +------+ - | |Tcl_WriteRaw <-- BioWrite| SSL |BIO_write <-- TlsOutputProc <-- Write| | - |socket| | BIO | | App | - | |Tcl_ReadRaw --> BioRead| |BIO_Read --> TlsInputProc --> Read| | - +------+ +-----+ +------+ + +------+ +---+ +---+ + | |Tcl_WriteRaw<--BioOutput|SSL|BIO_write<--TlsOutputProc<--Write| | + |socket| |BIO| |App| + | |Tcl_ReadRaw --> BioInput| |BIO_Read -->TlsInputProc --> Read| | + +------+ +---+ +---+ */ #include "tlsInt.h" #include @@ -43,11 +43,14 @@ * Side effects: * Sets the device into blocking or nonblocking mode. * *----------------------------------------------------------------------------- */ -static int TlsBlockModeProc(ClientData instanceData, int mode) { +static int TlsBlockModeProc( + ClientData instanceData, /* Connection state info */ + int mode) /* Blocking or non-blocking mode */ +{ State *statePtr = (State *) instanceData; if (mode == TCL_MODE_NONBLOCKING) { statePtr->flags |= TLS_TCL_ASYNC; } else { @@ -60,30 +63,33 @@ *----------------------------------------------------------------------------- * * TlsCloseProc -- * * This procedure is invoked by the generic IO level to perform channel - * type specific cleanup when a SSL socket based channel is closed. - * Called by the generic I/O layer whenever the Tcl_Close() function is - * used. + * type specific cleanup when a SSL socket based channel is closed. Called + * by the generic I/O layer whenever the Tcl_Close() function is used. * * Results: * 0 if successful or POSIX error code if failed. * * Side effects: * Closes the socket of the channel. * *----------------------------------------------------------------------------- */ -static int TlsCloseProc(ClientData instanceData, Tcl_Interp *interp) { +static int TlsCloseProc( + ClientData instanceData, /* Connection state info */ + Tcl_Interp *interp) /* Tcl interpreter to report errors to */ +{ State *statePtr = (State *) instanceData; dprintf("TlsCloseProc(%p)", (void *) statePtr); - /* Send shutdown notification. Will return 0 while in process, then 1 when complete. */ - /* Closes the write direction of the connection; the read direction is closed by the peer. */ - /* Does not affect socket state. Don't call after fatal error. */ + /* Send shutdown notification. Will return 0 while in process, then 1 when + complete. Only closes the write direction of the connection; the read + direction is closed by the peer. Does not affect socket state. Don't + call after fatal error. */ if (statePtr->ssl != NULL && !(statePtr->flags & TLS_TCL_HANDSHAKE_FAILED)) { BIO_flush(statePtr->bio); SSL_shutdown(statePtr->ssl); } @@ -100,13 +106,14 @@ * Similar to TlsCloseProc, but allows for separate close read and write * side of channel. * *----------------------------------------------------------------------------- */ -static int TlsClose2Proc(ClientData instanceData, /* The socket state. */ - Tcl_Interp *interp, /* For errors - can be NULL. */ - int flags) /* Flags to close read and/or write side of channel */ +static int TlsClose2Proc( + ClientData instanceData, /* Connection state info */ + Tcl_Interp *interp, /* Tcl interpreter to report errors to */ + int flags) /* Flags to close read/write side of channel */ { State *statePtr = (State *) instanceData; dprintf("TlsClose2Proc(%p)", (void *) statePtr); @@ -130,11 +137,15 @@ * Side effects: * Issues SSL_accept or SSL_connect * *----------------------------------------------------------------------------- */ -int Tls_WaitForConnect(State *statePtr, int *errorCodePtr, int handshakeFailureIsPermanent) { +int Tls_WaitForConnect( + State *statePtr, /* Connection state info */ + int *errorCodePtr, /* Storage for error code to return */ + int handshakeFailureIsPermanent) /* Is the connect failure permanent */ +{ unsigned long backingError; int err, rc = 0; int bioShouldRetry; *errorCodePtr = 0; @@ -239,15 +250,17 @@ dprintf("The connection is good"); *errorCodePtr = 0; break; case SSL_ERROR_SSL: - /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error */ - /* This includes certificate validation errors */ + /* A non-recoverable, fatal error in the SSL library occurred, + usually a protocol error. This includes certificate validation + errors. */ dprintf("SSL_ERROR_SSL: Got permanent fatal SSL error, aborting immediately"); if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) { - Tls_Error(statePtr, X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); + Tls_Error(statePtr, + X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); } if (backingError != 0) { Tls_Error(statePtr, ERR_reason_error_string(backingError)); } statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED; @@ -282,28 +295,31 @@ statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED; return -1; case SSL_ERROR_ZERO_RETURN: - /* Peer has closed the connection by sending the close_notify alert. Can't read, but can write. */ - /* Need to return an EOF, so channel is closed which will send an SSL_shutdown(). */ + /* Peer has closed the connection by sending the close_notify alert. + Can't read, but can write. Need to return an EOF, so channel is + closed which will send an SSL_shutdown(). */ dprintf("SSL_ERROR_ZERO_RETURN: Connect returned an invalid value..."); *errorCodePtr = ECONNRESET; Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert"); return -1; case SSL_ERROR_WANT_READ: - /* More data must be read from the underlying BIO layer in order to complete the actual SSL_*() operation. */ + /* More data must be read from the underlying BIO layer in order to + complete the actual SSL_*() operation. */ dprintf("SSL_ERROR_WANT_READ"); BIO_set_retry_read(statePtr->bio); *errorCodePtr = EAGAIN; - dprintf("ERR(SSL_ERROR_ZERO_RETURN, EAGAIN) "); + dprintf("ERR(SSL_ERROR_WANT_READ, EAGAIN) "); statePtr->want |= TCL_READABLE; return 0; case SSL_ERROR_WANT_WRITE: - /* There is data in the SSL buffer that must be written to the underlying BIO in order to complete the SSL_*() operation. */ + /* There is data in the SSL buffer that must be written to the + underlying BIO in order to complete the SSL_*() operation. */ dprintf("SSL_ERROR_WANT_WRITE"); BIO_set_retry_write(statePtr->bio); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_WRITE, EAGAIN) "); statePtr->want |= TCL_WRITABLE; @@ -326,28 +342,34 @@ *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_ACCEPT, EAGAIN) "); return 0; case SSL_ERROR_WANT_X509_LOOKUP: - /* App callback set by SSL_CTX_set_client_cert_cb has asked to be called again */ - /* The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again. */ + /* Application callback set by SSL_CTX_set_client_cert_cb has asked + to be called again. The operation did not complete because an + application callback set by SSL_CTX_set_client_cert_cb() has + asked to be called again. */ dprintf("SSL_ERROR_WANT_X509_LOOKUP"); BIO_set_retry_special(statePtr->bio); BIO_set_retry_reason(statePtr->bio, BIO_RR_SSL_X509_LOOKUP); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_X509_LOOKUP, EAGAIN) "); return 0; case SSL_ERROR_WANT_ASYNC: - /* Used with flag SSL_MODE_ASYNC, op didn't complete because an async engine is still processing data */ + /* Used with flag SSL_MODE_ASYNC, op didn't complete because an + async engine is still processing data */ case SSL_ERROR_WANT_ASYNC_JOB: - /* The asynchronous job could not be started because there were no async jobs available in the pool. */ + /* The asynchronous job could not be started because there were no + async jobs available in the pool. */ case SSL_ERROR_WANT_CLIENT_HELLO_CB: - /* The operation did not complete because an application callback set by SSL_CTX_set_client_hello_cb() has asked to be called again. */ + /* The operation did not complete because an application callback + set by SSL_CTX_set_client_hello_cb() has asked to be called again. */ #if OPENSSL_VERSION_NUMBER >= 0x30000000L case SSL_ERROR_WANT_RETRY_VERIFY: - /* The operation did not complete because a certificate verification callback has asked to be called again via SSL_set_retry_verify(3). */ + /* The operation did not complete because a certificate verification + callback has asked to be called again via SSL_set_retry_verify(3). */ #endif default: /* The operation did not complete and should be retried later. */ dprintf("Operation did not complete, call function again later"); *errorCodePtr = EAGAIN; @@ -383,19 +405,25 @@ * record is processed (e.g. decrypted) in one go and is buffered by OpenSSL * until it is read by the application via a call to SSL_read. * *----------------------------------------------------------------------------- */ -static int TlsInputProc(ClientData instanceData, char *buf, int bufSize, int *errorCodePtr) { +static int TlsInputProc( + ClientData instanceData, /* Connection state info */ + char *buf, /* Buffer to store data read from BIO */ + int bufSize, /* Buffer size in bytes */ + int *errorCodePtr) /* Storage for error code to return */ +{ unsigned long backingError; State *statePtr = (State *) instanceData; int bytesRead, err; *errorCodePtr = 0; dprintf("Read(%d)", bufSize); - /* Skip if user verify callback is still running */ + /* Abort if the user verify callback is still running to avoid triggering + * another call before the current one is complete. */ if (statePtr->flags & TLS_TCL_CALLBACK) { dprintf("Callback is running, reading 0 bytes"); return 0; } @@ -474,16 +502,18 @@ dprintf("SSL_ERROR_NONE"); dprintBuffer(buf, bytesRead); break; case SSL_ERROR_SSL: - /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error */ + /* A non-recoverable, fatal error in the SSL library occurred, + usually a protocol error. */ dprintf("SSL error, indicating that the connection has been aborted"); if (backingError != 0) { Tls_Error(statePtr, ERR_reason_error_string(backingError)); } else if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) { - Tls_Error(statePtr, X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); + Tls_Error(statePtr, + X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); } else { Tls_Error(statePtr, "Unknown SSL error"); } *errorCodePtr = ECONNABORTED; bytesRead = -1; @@ -498,29 +528,32 @@ } #endif break; case SSL_ERROR_WANT_READ: - /* Op did not complete due to not enough data was available. Retry later. */ + /* Operation did not complete due to not enough data was available. + Retry again later. */ dprintf("Got SSL_ERROR_WANT_READ, mapping this to EAGAIN"); *errorCodePtr = EAGAIN; bytesRead = -1; statePtr->want |= TCL_READABLE; BIO_set_retry_read(statePtr->bio); break; case SSL_ERROR_WANT_WRITE: - /* Op did not complete due to unable to send all data to the BIO. Retry later. */ + /* Operation did not complete due to unable to send all data to the + BIO. Retry again later. */ dprintf("Got SSL_ERROR_WANT_WRITE, mapping this to EAGAIN"); *errorCodePtr = EAGAIN; bytesRead = -1; statePtr->want |= TCL_WRITABLE; BIO_set_retry_write(statePtr->bio); break; case SSL_ERROR_WANT_X509_LOOKUP: - /* Op didn't complete since callback set by SSL_CTX_set_client_cert_cb() asked to be called again */ + /* Operation didn't complete since application callback set by + SSL_CTX_set_client_cert_cb() asked to be called again. */ dprintf("Got SSL_ERROR_WANT_X509_LOOKUP, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; bytesRead = -1; break; @@ -534,11 +567,12 @@ *errorCodePtr = 0; bytesRead = 0; Tls_Error(statePtr, "EOF reached"); } else if (backingError == 0 && bytesRead == -1) { - dprintf("I/O error occurred (errno = %lu)", (unsigned long) Tcl_GetErrno()); + dprintf("I/O error occurred (errno = %lu)", + (unsigned long) Tcl_GetErrno()); *errorCodePtr = Tcl_GetErrno(); bytesRead = -1; Tls_Error(statePtr, Tcl_ErrnoMsg(*errorCodePtr)); } else { @@ -548,20 +582,22 @@ Tls_Error(statePtr, ERR_reason_error_string(backingError)); } break; case SSL_ERROR_ZERO_RETURN: - /* Peer has closed the connection by sending the close_notify alert. Can't read, but can write. */ - /* Need to return an EOF, so channel is closed which will send an SSL_shutdown(). */ + /* Peer has closed the connection by sending the close_notify alert. + Can't read, but can write. Need to return an EOF, so channel is + closed which will send an SSL_shutdown(). */ dprintf("Got SSL_ERROR_ZERO_RETURN, this means an EOF has been reached"); bytesRead = 0; *errorCodePtr = 0; Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert"); break; case SSL_ERROR_WANT_ASYNC: - /* Used with flag SSL_MODE_ASYNC, op didn't complete because an async engine is still processing data */ + /* Used with flag SSL_MODE_ASYNC, operation didn't complete because + an async engine is still processing data. */ dprintf("Got SSL_ERROR_WANT_ASYNC, mapping this to EAGAIN"); *errorCodePtr = EAGAIN; bytesRead = -1; break; @@ -593,20 +629,26 @@ * Side effects: * Writes output on the output device of the channel. * *----------------------------------------------------------------------------- */ -static int TlsOutputProc(ClientData instanceData, const char *buf, int toWrite, int *errorCodePtr) { +static int TlsOutputProc( + ClientData instanceData, /* Connection state info */ + const char *buf, /* Buffer with data to write to BIO */ + int toWrite, /* Size of data to write in bytes */ + int *errorCodePtr) /* Storage for error code to return */ +{ unsigned long backingError; State *statePtr = (State *) instanceData; int written, err; *errorCodePtr = 0; dprintf("Write(%p, %d)", (void *) statePtr, toWrite); dprintBuffer(buf, toWrite); - /* Skip if user verify callback is still running */ + /* Abort if the user verify callback is still running to avoid triggering + * another call before the current one is complete. */ if (statePtr->flags & TLS_TCL_CALLBACK) { dprintf("Don't process output while callbacks are running"); written = -1; *errorCodePtr = EAGAIN; return -1; @@ -619,11 +661,12 @@ dprintf("Calling Tls_WaitForConnect"); tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 1); if (tlsConnect < 0) { - dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr); + dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", + tlsConnect, *errorCodePtr); written = -1; if (*errorCodePtr == ECONNRESET) { dprintf("Got connection reset"); /* Soft EOF */ @@ -673,13 +716,15 @@ backingError = ERR_get_error(); if (written <= 0) { /* The retry flag is set by the BIO_set_retry_* functions */ if (BIO_should_retry(statePtr->bio)) { - dprintf("Write failed with code %d, bytes written=%d: should retry", err, written); + dprintf("Write failed with code %d, bytes written=%d: should retry", + err, written); } else { - dprintf("Write failed with code %d, bytes written=%d: error condition", err, written); + dprintf("Write failed with code %d, bytes written=%d: error condition", + err, written); } /* These are the same as BIO_retry_type */ if (BIO_should_read(statePtr->bio)) { dprintf("BIO has insufficient data to read and return"); @@ -705,43 +750,48 @@ written = 0; } break; case SSL_ERROR_SSL: - /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error */ + /* A non-recoverable, fatal error in the SSL library occurred, + usually a protocol error */ dprintf("SSL error, indicating that the connection has been aborted"); if (backingError != 0) { Tls_Error(statePtr, ERR_reason_error_string(backingError)); } else if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) { - Tls_Error(statePtr, X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); + Tls_Error(statePtr, + X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); } else { Tls_Error(statePtr, "Unknown SSL error"); } *errorCodePtr = ECONNABORTED; written = -1; break; case SSL_ERROR_WANT_READ: - /* Op did not complete due to not enough data was available. Retry later. */ + /* Operation did not complete due to not enough data was available. + Retry again later. */ dprintf("Got SSL_ERROR_WANT_READ, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; statePtr->want |= TCL_READABLE; BIO_set_retry_read(statePtr->bio); break; case SSL_ERROR_WANT_WRITE: - /* Op did not complete due to unable to send all data to the BIO. Retry later. */ + /* Operation did not complete due to unable to send all data to the + BIO. Retry later. */ dprintf("Got SSL_ERROR_WANT_WRITE, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; statePtr->want |= TCL_WRITABLE; BIO_set_retry_write(statePtr->bio); break; case SSL_ERROR_WANT_X509_LOOKUP: - /* Op didn't complete since callback set by SSL_CTX_set_client_cert_cb() asked to be called again */ + /* Operation didn't complete since application callback set by + SSL_CTX_set_client_cert_cb() asked to be called again. */ dprintf("Got SSL_ERROR_WANT_X509_LOOKUP, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; break; @@ -768,20 +818,22 @@ Tls_Error(statePtr, ERR_reason_error_string(backingError)); } break; case SSL_ERROR_ZERO_RETURN: - /* Peer has closed the connection by sending the close_notify alert. Can't read, but can write. */ - /* Need to return an EOF, so channel is closed which will send an SSL_shutdown(). */ + /* Peer has closed the connection by sending the close_notify alert. + Can't read, but can write. Need to return an EOF, so channel is + closed which will send an SSL_shutdown(). */ dprintf("Got SSL_ERROR_ZERO_RETURN, this means an EOF has been reached"); *errorCodePtr = 0; written = 0; Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert"); break; case SSL_ERROR_WANT_ASYNC: - /* Used with flag SSL_MODE_ASYNC, op didn't complete because an async engine is still processing data */ + /* Used with flag SSL_MODE_ASYNC, op didn't complete because an + async engine is still processing data */ dprintf("Got SSL_ERROR_WANT_ASYNC, mapping this to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; break; @@ -805,11 +857,14 @@ * Results: * Tcl_Channel or NULL if none. * *----------------------------------------------------------------------------- */ -Tcl_Channel Tls_GetParent(State *statePtr, int maskFlags) { +Tcl_Channel Tls_GetParent( + State *statePtr, /* Connection state info */ + int maskFlags) /* Which flags to process */ +{ dprintf("Requested to get parent of channel %p", statePtr->self); if ((statePtr->flags & ~maskFlags) & TLS_TCL_FASTPATH) { dprintf("Asked to get the parent channel while we are using FastPath -- returning NULL"); return NULL; @@ -832,11 +887,12 @@ * Updates channel option to new value. * *----------------------------------------------------------------------------- */ static int -TlsSetOptionProc(ClientData instanceData, /* Socket state. */ +TlsSetOptionProc( + ClientData instanceData, /* Socket state. */ Tcl_Interp *interp, /* For errors - can be NULL. */ const char *optionName, /* Name of the option to set the value for, or * NULL to get all options and their values. */ const char *optionValue) /* Value for option. */ { @@ -875,14 +931,15 @@ * None. * *------------------------------------------------------------------- */ static int -TlsGetOptionProc(ClientData instanceData, /* Socket state. */ +TlsGetOptionProc( + ClientData instanceData, /* Socket state. */ Tcl_Interp *interp, /* For errors - can be NULL. */ - const char *optionName, /* Name of the option to retrieve the value for, or - * NULL to get all options and their values. */ + const char *optionName, /* Name of the option to retrieve the value for, + * or NULL to get all options and their values. */ Tcl_DString *optionValue) /* Where to store the computed value initialized by caller. */ { State *statePtr = (State *) instanceData; Tcl_Channel parent = Tls_GetParent(statePtr, TLS_TCL_FASTPATH); Tcl_DriverGetOptionProc *getOptionProc; @@ -890,11 +947,12 @@ dprintf("Called"); /* Pass to parent */ getOptionProc = Tcl_ChannelGetOptionProc(Tcl_GetChannelType(parent)); if (getOptionProc != NULL) { - return (*getOptionProc)(Tcl_GetChannelInstanceData(parent), interp, optionName, optionValue); + return (*getOptionProc)(Tcl_GetChannelInstanceData(parent), interp, + optionName, optionValue); } else if (optionName == (char*) NULL) { /* * Request is query for all options, this is ok. */ return TCL_OK; @@ -920,11 +978,13 @@ * Side effects: * Creates notification event. * *----------------------------------------------------------------------------- */ -static void TlsChannelHandlerTimer(ClientData clientData) { +static void TlsChannelHandlerTimer( + ClientData clientData) /* Socket state. */ +{ State *statePtr = (State *) clientData; int mask = statePtr->want; /* Init to SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE */ dprintf("Called"); @@ -972,24 +1032,25 @@ * will be seen by TCL. * *----------------------------------------------------------------------------- */ static void -TlsWatchProc(ClientData instanceData, /* The socket state. */ +TlsWatchProc( + ClientData instanceData, /* Connection state info */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and TCL_EXCEPTION. */ { Tcl_Channel parent; State *statePtr = (State *) instanceData; Tcl_DriverWatchProc *watchProc; int pending = 0; - dprintf("TlsWatchProc(0x%x)", mask); + dprintf("Called with mask 0x%02x", mask); dprintFlags(statePtr); - /* Pretend to be dead as long as the verify callback is running. - * Otherwise that callback could be invoked recursively. */ + /* Abort if the user verify callback is still running to avoid triggering + * another call before the current one is complete. */ if (statePtr->flags & TLS_TCL_CALLBACK) { dprintf("Callback is on-going, doing nothing"); return; } @@ -1005,16 +1066,15 @@ return; } statePtr->watchMask = mask; - /* No channel handlers any more. We will be notified automatically - * about events on the channel below via a call to our - * 'TransformNotifyProc'. But we have to pass the interest down now. - * We are allowed to add additional 'interest' to the mask if we want - * to. But this transformation has no such interest. It just passes - * the request down, unchanged. + /* No channel handlers any more. We will be notified automatically about + * events on the channel below via a call to our 'TransformNotifyProc'. But + * we have to pass the interest down now. We are allowed to add additional + * 'interest' to the mask if we want to, but this transformation has no + * such interest. It just passes the request down, unchanged. */ dprintf("Registering our interest in the lower channel (chan=%p)", (void *) parent); watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(parent)); watchProc(Tcl_GetChannelInstanceData(parent), mask); @@ -1058,40 +1118,43 @@ * Side effects: * None. * *----------------------------------------------------------------------------- */ -static int TlsGetHandleProc(ClientData instanceData, /* Socket state. */ +static int TlsGetHandleProc( + ClientData instanceData, /* Socket state. */ int direction, /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr) /* Handle associated with the channel */ { State *statePtr = (State *) instanceData; - return Tcl_GetChannelHandle(Tls_GetParent(statePtr, TLS_TCL_FASTPATH), direction, handlePtr); + return Tcl_GetChannelHandle(Tls_GetParent(statePtr, TLS_TCL_FASTPATH), + direction, handlePtr); } /* *----------------------------------------------------------------------------- * * TlsNotifyProc -- * * This procedure is invoked by the generic IO level to notify the channel - * that an event has occurred on the underlying channel. It is used by stacked channel drivers that - * wish to be notified of events that occur on the underlying (stacked) - * channel. + * that an event has occurred on the underlying channel. It is used by + * stacked channel drivers that wish to be notified of events that occur + * on the underlying (stacked) channel. * * Results: * Type of event or 0 if failed * * Side effects: * May process the incoming event by itself. * *----------------------------------------------------------------------------- */ -static int TlsNotifyProc(ClientData instanceData, /* Socket state. */ - int mask) /* type of event that occurred: - * OR-ed combination of TCL_READABLE or TCL_WRITABLE */ +static int TlsNotifyProc( + ClientData instanceData, /* Socket state. */ + int mask) /* type of event that occurred: OR-ed + * combination of TCL_READABLE or TCL_WRITABLE */ { State *statePtr = (State *) instanceData; int errorCode = 0; dprintf("Called"); Index: generic/tlsInt.h ================================================================== --- generic/tlsInt.h +++ generic/tlsInt.h @@ -163,41 +163,42 @@ } /* * Defines for State.flags */ -#define TLS_TCL_ASYNC (1<<0) /* non-blocking mode */ +#define TLS_TCL_ASYNC (1<<0) /* Non-blocking mode */ #define TLS_TCL_SERVER (1<<1) /* Server-Side */ #define TLS_TCL_INIT (1<<2) /* Initializing connection */ #define TLS_TCL_DEBUG (1<<3) /* Show debug tracing */ #define TLS_TCL_CALLBACK (1<<4) /* In a callback, prevent update * looping problem. [Bug 1652380] */ #define TLS_TCL_HANDSHAKE_FAILED (1<<5) /* Set on handshake failures and once set, all * further I/O will result in ECONNABORTED errors. */ -#define TLS_TCL_FASTPATH (1<<6) /* The parent channel is being used directly by the SSL library */ +#define TLS_TCL_FASTPATH (1<<6) /* The parent channel is being used + * directly by the SSL library. */ #define TLS_TCL_DELAY (5) /* * This structure describes the per-instance state of an SSL channel. * * The SSL processing context is maintained here, in the ClientData */ typedef struct State { - Tcl_Channel self; /* this socket channel */ - Tcl_TimerToken timer; - - int flags; /* see State.flags above */ - int watchMask; /* current WatchProc mask */ - int want; /* pending wants from OpenSSL */ - int mode; /* current mode of parent channel */ - - Tcl_Interp *interp; /* interpreter in which this resides */ - Tcl_Obj *callback; /* script called for tracing, info, and errors */ - Tcl_Obj *password; /* script called for certificate password */ - Tcl_Obj *vcmd; /* script called to verify or validate protocol config */ - - int vflags; /* verify flags */ + Tcl_Channel self; /* This socket channel */ + Tcl_TimerToken timer; /* I/O timer handle */ + + int flags; /* See State.flags above */ + int watchMask; /* Current WatchProc mask */ + int want; /* Pending wants from OpenSSL */ + int mode; /* Current mode of parent channel */ + + Tcl_Interp *interp; /* Interpreter in which this resides */ + Tcl_Obj *callback; /* Script called for tracing, info, and errors */ + Tcl_Obj *password; /* Script called for certificate password */ + Tcl_Obj *vcmd; /* Script called to verify or validate protocol config */ + + int vflags; /* Verify flags */ SSL *ssl; /* Struct for SSL processing */ SSL_CTX *ctx; /* SSL Context */ BIO *bio; /* Struct for SSL processing */ BIO *p_bio; /* Parent BIO (that is layered on Tcl_Channel) */ Index: win/makefile.vc ================================================================== --- win/makefile.vc +++ win/makefile.vc @@ -38,10 +38,11 @@ # SSL_INSTALL_FOLDER = with the OpenSSL installation folder following. PRJ_INCLUDES = -I"$(SSL_INSTALL_FOLDER)\include" -I"$(OPENSSL_INSTALL_DIR)\include" -I"$(TMP_DIR)" # Define any additional compiler flags that might be required for the project PRJ_DEFINES = -D NO_SSL2 -D NO_SSL3 /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D__STDC_WANT_SECURE_LIB__=1 +# /DTCLTLS_SSL_USE_FASTPATH # /DTCLEXT_TCLTLS_DEBUG # # SSL Libs: # 1. ${LIBCRYPTO}.dll @@ -86,11 +87,11 @@ !IF EXIST($(DTPLITE)) "$(TCLSH)" "$(DTPLITE)" -o "$DOCDIR" html "$(ROOT)\doc" "$(TCLSH)" "$(DTPLITE)" -o "$DOCDIR" nroff "$(ROOT)\doc" !ENDIF -docs: make-docs-n make-docs-html +docs: make-docs-n make-docs-html all: setup default-target clean: default-clean