|
1 |
| -/* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. |
| 1 | +/* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. |
2 | 2 |
|
3 | 3 | This program is free software; you can redistribute it and/or modify
|
4 | 4 | it under the terms of the GNU General Public License as published by
|
@@ -1885,63 +1885,101 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
|
1885 | 1885 | static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr)
|
1886 | 1886 | {
|
1887 | 1887 | SSL *ssl;
|
1888 |
| - X509 *server_cert; |
1889 |
| - char *cp1, *cp2; |
1890 |
| - char buf[256]; |
| 1888 | + X509 *server_cert= NULL; |
| 1889 | + char *cn= NULL; |
| 1890 | + int cn_loc= -1; |
| 1891 | + ASN1_STRING *cn_asn1= NULL; |
| 1892 | + X509_NAME_ENTRY *cn_entry= NULL; |
| 1893 | + X509_NAME *subject= NULL; |
| 1894 | + int ret_validation= 1; |
| 1895 | + |
1891 | 1896 | DBUG_ENTER("ssl_verify_server_cert");
|
1892 | 1897 | DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
|
1893 | 1898 |
|
1894 | 1899 | if (!(ssl= (SSL*)vio->ssl_arg))
|
1895 | 1900 | {
|
1896 | 1901 | *errptr= "No SSL pointer found";
|
1897 |
| - DBUG_RETURN(1); |
| 1902 | + goto error; |
1898 | 1903 | }
|
1899 | 1904 |
|
1900 | 1905 | if (!server_hostname)
|
1901 | 1906 | {
|
1902 | 1907 | *errptr= "No server hostname supplied";
|
1903 |
| - DBUG_RETURN(1); |
| 1908 | + goto error; |
1904 | 1909 | }
|
1905 | 1910 |
|
1906 | 1911 | if (!(server_cert= SSL_get_peer_certificate(ssl)))
|
1907 | 1912 | {
|
1908 | 1913 | *errptr= "Could not get server certificate";
|
1909 |
| - DBUG_RETURN(1); |
| 1914 | + goto error; |
1910 | 1915 | }
|
1911 | 1916 |
|
1912 | 1917 | if (X509_V_OK != SSL_get_verify_result(ssl))
|
1913 | 1918 | {
|
1914 | 1919 | *errptr= "Failed to verify the server certificate";
|
1915 |
| - X509_free(server_cert); |
1916 |
| - DBUG_RETURN(1); |
| 1920 | + goto error; |
1917 | 1921 | }
|
1918 | 1922 | /*
|
1919 | 1923 | We already know that the certificate exchanged was valid; the SSL library
|
1920 | 1924 | handled that. Now we need to verify that the contents of the certificate
|
1921 | 1925 | are what we expect.
|
1922 | 1926 | */
|
1923 | 1927 |
|
1924 |
| - X509_NAME_oneline(X509_get_subject_name(server_cert), buf, sizeof(buf)); |
1925 |
| - X509_free (server_cert); |
| 1928 | + /* |
| 1929 | + Some notes for future development |
| 1930 | + We should check host name in alternative name first and then if needed check in common name. |
| 1931 | + Currently yssl doesn't support alternative name. |
| 1932 | + openssl 1.0.2 support X509_check_host method for host name validation, we may need to start using |
| 1933 | + X509_check_host in the future. |
| 1934 | + */ |
1926 | 1935 |
|
1927 |
| - DBUG_PRINT("info", ("hostname in cert: %s", buf)); |
1928 |
| - cp1= strstr(buf, "/CN="); |
1929 |
| - if (cp1) |
| 1936 | + subject= X509_get_subject_name((X509 *) server_cert); |
| 1937 | + // Find the CN location in the subject |
| 1938 | + cn_loc= X509_NAME_get_index_by_NID(subject, NID_commonName, -1); |
| 1939 | + if (cn_loc < 0) |
1930 | 1940 | {
|
1931 |
| - cp1+= 4; /* Skip the "/CN=" that we found */ |
1932 |
| - /* Search for next / which might be the delimiter for email */ |
1933 |
| - cp2= strchr(cp1, '/'); |
1934 |
| - if (cp2) |
1935 |
| - *cp2= '\0'; |
1936 |
| - DBUG_PRINT("info", ("Server hostname in cert: %s", cp1)); |
1937 |
| - if (!strcmp(cp1, server_hostname)) |
1938 |
| - { |
1939 |
| - /* Success */ |
1940 |
| - DBUG_RETURN(0); |
1941 |
| - } |
| 1941 | + *errptr= "Failed to get CN location in the certificate subject"; |
| 1942 | + goto error; |
| 1943 | + } |
| 1944 | + |
| 1945 | + // Get the CN entry for given location |
| 1946 | + cn_entry= X509_NAME_get_entry(subject, cn_loc); |
| 1947 | + if (cn_entry == NULL) |
| 1948 | + { |
| 1949 | + *errptr= "Failed to get CN entry using CN location"; |
| 1950 | + goto error; |
1942 | 1951 | }
|
| 1952 | + |
| 1953 | + // Get CN from common name entry |
| 1954 | + cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry); |
| 1955 | + if (cn_asn1 == NULL) |
| 1956 | + { |
| 1957 | + *errptr= "Failed to get CN from CN entry"; |
| 1958 | + goto error; |
| 1959 | + } |
| 1960 | + |
| 1961 | + cn= (char *) ASN1_STRING_data(cn_asn1); |
| 1962 | + |
| 1963 | + // There should not be any NULL embedded in the CN |
| 1964 | + if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn)) |
| 1965 | + { |
| 1966 | + *errptr= "NULL embedded in the certificate CN"; |
| 1967 | + goto error; |
| 1968 | + } |
| 1969 | + |
| 1970 | + DBUG_PRINT("info", ("Server hostname in cert: %s", cn)); |
| 1971 | + if (!strcmp(cn, server_hostname)) |
| 1972 | + { |
| 1973 | + /* Success */ |
| 1974 | + ret_validation= 0; |
| 1975 | + } |
| 1976 | + |
1943 | 1977 | *errptr= "SSL certificate validation failure";
|
1944 |
| - DBUG_RETURN(1); |
| 1978 | + |
| 1979 | +error: |
| 1980 | + if (server_cert != NULL) |
| 1981 | + X509_free (server_cert); |
| 1982 | + DBUG_RETURN(ret_validation); |
1945 | 1983 | }
|
1946 | 1984 |
|
1947 | 1985 | #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
|
|
0 commit comments