hostname.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright (C) 2017. See AUTHORS.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package openssl
  15. /*
  16. #include <openssl/ssl.h>
  17. #include <openssl/conf.h>
  18. #include <openssl/x509.h>
  19. #ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
  20. #define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1
  21. #define X509_CHECK_FLAG_NO_WILDCARDS 0x2
  22. extern int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
  23. unsigned int flags, char **peername);
  24. extern int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
  25. unsigned int flags);
  26. extern int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
  27. unsigned int flags);
  28. #endif
  29. */
  30. import "C"
  31. import (
  32. "errors"
  33. "net"
  34. "unsafe"
  35. )
  36. var (
  37. ValidationError = errors.New("Host validation error")
  38. )
  39. type CheckFlags int
  40. const (
  41. AlwaysCheckSubject CheckFlags = C.X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
  42. NoWildcards CheckFlags = C.X509_CHECK_FLAG_NO_WILDCARDS
  43. )
  44. // CheckHost checks that the X509 certificate is signed for the provided
  45. // host name. See http://www.openssl.org/docs/crypto/X509_check_host.html for
  46. // more. Note that CheckHost does not check the IP field. See VerifyHostname.
  47. // Specifically returns ValidationError if the Certificate didn't match but
  48. // there was no internal error.
  49. func (c *Certificate) CheckHost(host string, flags CheckFlags) error {
  50. chost := unsafe.Pointer(C.CString(host))
  51. defer C.free(chost)
  52. rv := C.X509_check_host(c.x, (*C.uchar)(chost), C.size_t(len(host)),
  53. C.uint(flags), nil)
  54. if rv > 0 {
  55. return nil
  56. }
  57. if rv == 0 {
  58. return ValidationError
  59. }
  60. return errors.New("hostname validation had an internal failure")
  61. }
  62. // CheckEmail checks that the X509 certificate is signed for the provided
  63. // email address. See http://www.openssl.org/docs/crypto/X509_check_host.html
  64. // for more.
  65. // Specifically returns ValidationError if the Certificate didn't match but
  66. // there was no internal error.
  67. func (c *Certificate) CheckEmail(email string, flags CheckFlags) error {
  68. cemail := unsafe.Pointer(C.CString(email))
  69. defer C.free(cemail)
  70. rv := C.X509_check_email(c.x, (*C.uchar)(cemail), C.size_t(len(email)),
  71. C.uint(flags))
  72. if rv > 0 {
  73. return nil
  74. }
  75. if rv == 0 {
  76. return ValidationError
  77. }
  78. return errors.New("email validation had an internal failure")
  79. }
  80. // CheckIP checks that the X509 certificate is signed for the provided
  81. // IP address. See http://www.openssl.org/docs/crypto/X509_check_host.html
  82. // for more.
  83. // Specifically returns ValidationError if the Certificate didn't match but
  84. // there was no internal error.
  85. func (c *Certificate) CheckIP(ip net.IP, flags CheckFlags) error {
  86. cip := unsafe.Pointer(&ip[0])
  87. rv := C.X509_check_ip(c.x, (*C.uchar)(cip), C.size_t(len(ip)),
  88. C.uint(flags))
  89. if rv > 0 {
  90. return nil
  91. }
  92. if rv == 0 {
  93. return ValidationError
  94. }
  95. return errors.New("ip validation had an internal failure")
  96. }
  97. // VerifyHostname is a combination of CheckHost and CheckIP. If the provided
  98. // hostname looks like an IP address, it will be checked as an IP address,
  99. // otherwise it will be checked as a hostname.
  100. // Specifically returns ValidationError if the Certificate didn't match but
  101. // there was no internal error.
  102. func (c *Certificate) VerifyHostname(host string) error {
  103. var ip net.IP
  104. if len(host) >= 3 && host[0] == '[' && host[len(host)-1] == ']' {
  105. ip = net.ParseIP(host[1 : len(host)-1])
  106. } else {
  107. ip = net.ParseIP(host)
  108. }
  109. if ip != nil {
  110. return c.CheckIP(ip, 0)
  111. }
  112. return c.CheckHost(host, 0)
  113. }