You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The existing TLS interface both for connection strings and connection
configuration objects is too strict and, at the same time, is not clear
about the role of additional TLS options such as verifying server
certificates are issued or revoked by a CA in a given chain.
Also, there is currently no option to verify the server identity
comparing the hostname and the common name specified by its own
certificate.
This patch introduces some changes to relax the validation requirements
of TLS-related options and to enable implicit or explicit server
identity checks.
Two specific working TLS modes - "VERIFY_CA" and "VERIFY_IDENTITY" are
now available to enable these certificate validation features with
connection strings, and a new secure context option
"checkServerIdentity" is now available and allow applications to verify
the server hostname using the details of the server certificate. This
can happen implicitly using a custom function or using the builtin
Node.js validation function.
https://nodejs.org/docs/v12.0.0/api/tls.html#tls_tls_checkserveridentity_hostname_cert
Copy file name to clipboardExpand all lines: docs/tutorial/Secure_Sessions.md
+105-7Lines changed: 105 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -166,19 +166,22 @@ Applications are free to use older TLSv1 and TLSv1.1 compatible ciphersuites (li
166
166
167
167
Non-TLS ciphersuites, including the `MD5`, `SSLv3` and other older sets are not supported and will be ignored if the application wants to use them. If none of the ciphers provided by the application is actually supported by the client, an error will be thrown.
168
168
169
-
#### Certificate authority validation
169
+
#### Certificate Authority Validation
170
170
171
171
When creating a connection to the database using TLS, the connector can validate if the server certificate was signed by a certificate authority (CA) and, at the same time, ensure that the certificate was not revoked by that same authority, or any other in a given chain of trust.
172
172
173
173
Just like with TLS-related core Node.js APIs, an application can provide one or more PEM formatted CA certificates and certificate revocation lists (CRL). The [secure context](https://nodejs.org/docs/v12.0.0/api/tls.html#tls_tls_createsecurecontext_options) uses a list of well-known CAs curated by Mozilla, which are completely replaced by the list of CAs provided by an application. This means that if the certificate was not signed by the root CA, the entire chain of trust down to the signing CA, should be included in the list. The same is true for the certificate revocation lists, because each CA has its own.
174
174
175
-
Verifying if the server certificate was signed by the root CA can be done by providing the path to the CA file:
175
+
Verifying if the server certificate was signed by the root CA can be done by providing the path to the CA file. When using a connection string, this feature needs to be explicitly enabled by setting value of `ssl-mode` to `VERIFY_CA` or `VERIFY_IDENTITY` (which will also validate the server identity against its own certificate).
176
+
177
+
> **IMPORTANT**<br />
178
+
> When using a connection string, if the `ssl-mode` option is not set whilst providing a path to a certificate authority file, the verification does not happen and the client will yield a warning message.
> Due to the constraints imposed by connection strings, the fact that all core Node.js TLS-related APIs expect PEM file content as input, and the fact that Node.js and OpenSSL cannot verify CRLs concatenated in a single file, it is strongly recommended that applications always use a connection configuration object to specify one or more PEM files for CAs and CRLs using "fs.readFileSync()".
357
360
361
+
### Checking the Server Identity
362
+
363
+
Besides verifying if the server certificate was signed or revoked by a certificate in a given authority chain, it is also possible to additionally verify if the server is the effective owner of the certificate, by comparing the server hostname and the common name specifified by the certificate, according to a specific set of prerequisites. This check is only performed if the certificate first passes all the other checks, such as being issued by a given CA (required).
364
+
365
+
When using a connection configuration object, this can be done by providing an additional `checkServerIdentity` property as part of the secure context. If its value is `true`, the server identity check will happen using the builtin [`tls.checkServerIdentity()`](https://nodejs.org/docs/v12.0.0/api/tls.html#tls_tls_checkserveridentity_hostname_cert) function, which expects both the server hostname and certificate common name to be exactly the same.
console.log(err.message); // Hostname/IP does not match certificate's altnames: Host: localhost. is not cert's CN: example.com
390
+
});
391
+
```
392
+
393
+
An application can specify its own set of requirements to determine if the server identity is valid. This can be done by providing a custom `checkServerIdentity()` function. As an example, this can be useful, for instance to allow subdomains.
394
+
395
+
```js
396
+
constfs=require('fs')
397
+
constmysqlx=require('@mysql/xdevapi');
398
+
constpath=require('path');
399
+
400
+
let options = {
401
+
host:'dev.mysql.com',
402
+
tls: {
403
+
ca:path.join('/', 'path', 'to', 'ca.pem'),
404
+
checkServerIdentity (hostname, cert) {
405
+
// Checks if the domain is the same.
406
+
if (cert.subject.CN===hostname.substring(hostname.length-cert.subject.CN.length)) {
407
+
returntrue;
408
+
}
409
+
410
+
// Instead of being thrown, the error needs to be returned back to the client.
411
+
returnnewError(`"${hostname}" is not a valid subdomain of "${cert.subject.cn}"`);
console.log(err.message); // "dev.mysql.com" is not a valid subdomain of "example.com"
426
+
});
427
+
```
428
+
429
+
By default, if the `checkServerIdentity` property is not specified, the check will not be performed.
430
+
431
+
> **IMPORTANT**<br />
432
+
> Custom `checkServerIdentity()` functions should "return" all errors instead "throwing" them. Further implementation details are availabe in the official Node.js [documentation](https://nodejs.org/docs/v12.0.0/api/tls.html#tls_tls_checkserveridentity_hostname_cert).
433
+
434
+
When using a connection string, the API is a little bit more restricted. The only possibility is to set the value of the `ssl-mode` option to `VERIFY_IDENTITY` in order to explicitly enable the server identity check using the builtin `tls.checkServerIdentity()` function.
Copy file name to clipboardExpand all lines: lib/constants/errors.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -64,9 +64,9 @@ exports.MESSAGES = {
64
64
ER_DEVAPI_BAD_TLS_CA_PATH: 'The certificate authority (CA) file path is not valid.',
65
65
ER_DEVAPI_BAD_TLS_CRL_PATH: 'The certificate revocation list (CRL) file path is not valid.',
66
66
ER_DEVAPI_BAD_TLS_CIPHERSUITE_LIST: '%s is not a valid TLS ciphersuite list format.',
67
-
ER_DEVAPI_BAD_TLS_OPTIONS: 'Additional TLS options cannot be specified when TLS is disabled.',
68
67
ER_DEVAPI_BAD_TLS_VERSION: '"%s" is not a valid TLS protocol version. Should be one of %s.',
69
68
ER_DEVAPI_BAD_TLS_VERSION_LIST: '"%s" is not a valid TLS protocol list format.',
69
+
ER_DEVAPI_CERTIFICATE_AUTHORITY_REQUIRED: '%s requires a certificate authority.',
70
70
ER_DEVAPI_COLLECTION_OPTIONS_NOT_SUPPORTED: 'Your MySQL server does not support the requested operation. Please update to MySQL 8.0.19 or a later version.',
71
71
ER_DEVAPI_CONNECTION_CLOSED: 'This session was closed. Use "mysqlx.getSession()" or "mysqlx.getClient()" to create a new one.',
72
72
ER_DEVAPI_CONNECTION_TIMEOUT: 'Connection attempt to the server was aborted. Timeout of %d ms was exceeded.',
Copy file name to clipboardExpand all lines: lib/constants/warnings.js
+2-1Lines changed: 2 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -44,7 +44,8 @@ exports.MESSAGES = {
44
44
WARN_DEPRECATED_TABLE_UPDATE_EXPR_ARGUMENT: 'Passing an expression in Table.update() is a deprecated behavior and will not be supported in future versions. Use TableUpdate.where() instead.',
45
45
WARN_DEPRECATED_TABLE_INSERT_OBJECT_ARGUMENT: 'Passing objects to Table.insert() is a deprecated behavior and will not be supported in future versions.',
46
46
WARN_DEPRECATED_RESULT_GET_AFFECTED_ROWS_COUNT: 'Result.getAffectedRowsCount() is deprecated and will be removed in future versions. Use Result.getAffectedItemsCount() instead.',
47
-
WARN_DEPRECATED_SET_OFFSET: 'setOffset() is deprecated and will be removed in future versions. Use offset() instead.'
47
+
WARN_DEPRECATED_SET_OFFSET: 'setOffset() is deprecated and will be removed in future versions. Use offset() instead.',
48
+
WARN_STRICT_CERTIFICATE_VALIDATION: 'To verify if the server certificate was signed by a given certificate authority "ssl-mode" must be either "VERIFY_CA" or "VERIFY_IDENTITY".'
consterror='The X Plugin version installed in the server does not support TLS. Check https://dev.mysql.com/doc/refman/8.0/en/x-plugin-ssl-connections.html for more details on how to enable secure connections.';
47
-
48
-
returnmysqlx.getSession(secureConfig)
49
-
.then(()=>expect.fail())
50
-
.catch(err=>{
51
-
expect(err.message).to.equal(error);
52
-
});
53
-
});
43
+
mysqlx.getSession(uri)
44
+
.then(session=>{
45
+
returnsession.close();
46
+
})
47
+
.catch(err=>{
48
+
// errors in should be passed as JSON to the parent process via stderr
0 commit comments