]> Sergey Matveev's repositories - tofuproxy.git/blob - dane.go
d3218dda2509b6e9f595513899383d10266402d4
[tofuproxy.git] / dane.go
1 /*
2 tofuproxy -- HTTP proxy with TLS certificates management
3 Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package tofuproxy
19
20 import (
21         "crypto/sha256"
22         "crypto/sha512"
23         "crypto/x509"
24         "encoding/hex"
25         "fmt"
26         "log"
27         "strings"
28
29         "github.com/miekg/dns"
30 )
31
32 var DNSSrv string
33
34 func dane(addr string, cert *x509.Certificate) (bool, bool) {
35         if DNSSrv == "" {
36                 return false, false
37         }
38         host := addr
39         port := "443"
40         cols := strings.Split(addr, ":")
41         if len(cols) > 1 {
42                 host = cols[0]
43                 port = cols[1]
44         }
45         m := new(dns.Msg)
46         m.SetQuestion(dns.Fqdn(fmt.Sprintf("_%s._tcp.%s", port, host)), dns.TypeTLSA)
47         msg, err := dns.Exchange(m, DNSSrv)
48         if err != nil {
49                 log.Printf("DNS: %+v\n", err)
50                 return false, false
51         }
52         if msg.MsgHdr.Rcode != dns.RcodeSuccess {
53                 return false, false
54         }
55         exists := false
56         for _, answer := range msg.Answer {
57                 tlsa, ok := answer.(*dns.TLSA)
58                 if !ok {
59                         continue
60                 }
61                 if tlsa.Usage != 3 {
62                         // Non EE
63                         continue
64                 }
65                 exists = true
66                 var toMatch []byte
67                 switch tlsa.Selector {
68                 case 0:
69                         toMatch = cert.Raw
70                 case 1:
71                         toMatch = cert.RawSubjectPublicKeyInfo
72                 }
73                 var hsh []byte
74                 switch tlsa.MatchingType {
75                 case 0:
76                         hsh = toMatch
77                 case 1:
78                         our := sha256.Sum256(toMatch)
79                         hsh = our[:]
80                 case 2:
81                         our := sha512.Sum512(toMatch)
82                         hsh = our[:]
83                 }
84                 if tlsa.Certificate == hex.EncodeToString(hsh) {
85                         return true, true
86                 }
87         }
88         return exists, false
89 }