transport/tlscommon/validhostname.go (84 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // Copyright (c) 2009 The Go Authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file contains code adapted from golang's crypto/x509/verify.go package tlscommon import ( "strings" "unicode/utf8" ) func matchHostnames(pattern, host string) bool { pattern = toLowerCaseASCII(pattern) host = toLowerCaseASCII(strings.TrimSuffix(host, ".")) if len(pattern) == 0 || len(host) == 0 { return false } patternParts := strings.Split(pattern, ".") hostParts := strings.Split(host, ".") if len(patternParts) != len(hostParts) { return false } for i, patternPart := range patternParts { if i == 0 && patternPart == "*" { continue } if patternPart != hostParts[i] { return false } } return true } // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use // an explicitly ASCII function to avoid any sharp corners resulting from // performing Unicode operations on DNS labels. func toLowerCaseASCII(in string) string { // If the string is already lower-case then there's nothing to do. isAlreadyLowerCase := true for _, c := range in { if c == utf8.RuneError { // If we get a UTF-8 error then there might be // upper-case ASCII bytes in the invalid sequence. isAlreadyLowerCase = false break } if 'A' <= c && c <= 'Z' { isAlreadyLowerCase = false break } } if isAlreadyLowerCase { return in } out := []byte(in) for i, c := range out { if 'A' <= c && c <= 'Z' { out[i] += 'a' - 'A' } } return string(out) } // validHostname reports whether host is a valid hostname that can be matched or // matched against according to RFC 6125 2.2, with some leniency to accommodate // legacy values. func validHostname(host string, isPattern bool) bool { if !isPattern { host = strings.TrimSuffix(host, ".") } if len(host) == 0 { return false } for i, part := range strings.Split(host, ".") { if part == "" { // Empty label. return false } if isPattern && i == 0 && part == "*" { // Only allow full left-most wildcards, as those are the only ones // we match, and matching literal '*' characters is probably never // the expected behavior. continue } for j, c := range part { if 'a' <= c && c <= 'z' { continue } if '0' <= c && c <= '9' { continue } if 'A' <= c && c <= 'Z' { continue } if c == '-' && j != 0 { continue } if c == '_' { // Not a valid character in hostnames, but commonly // found in deployments outside the WebPKI. continue } return false } } return true }