|
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