Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"crypto/x509/pkix"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
"math/big"
mathrand "math/rand"
Expand Down Expand Up @@ -235,15 +236,23 @@ func matchClientCert(u *url.URL) tls.Certificate {
var bestMatchScore int

splitPath := strings.Split(u.Path, "/")
splitPathLen := len(splitPath)

muClientCerts.RLock()
for i, c := range clientCerts {
if u.Host != c.Host {
continue
}
certPathLen := len(c.Path)
var l int
if splitPathLen < certPathLen {
l = splitPathLen
} else {
l = certPathLen
}
score := 1
for i, p := range splitPath {
if p == c.Path[i] {
for i := 0; i < l; i++ {
if splitPath[i] == c.Path[i] {
score++
}
}
Expand Down Expand Up @@ -403,3 +412,25 @@ func saveTOFU() {
time.Sleep(10 * time.Minute)
}
}

// Return a PEM certificate by first trying to interpret the argument as the
// certificate data and if that fails as a path to a certificate.
func loadCertificate(certificate string) ([]byte, error) {
if strings.HasPrefix(certificate, "-----BEGIN ") {
return []byte(certificate), nil
} else {
if strings.HasPrefix(certificate, "~") {
h, err := os.UserHomeDir()
if err != nil {
return []byte{}, err
}
certificate = strings.Replace(certificate, "~", h, 1)
}
keyPEM, err := ioutil.ReadFile(certificate)
if err != nil {
return []byte{}, err
}
return keyPEM, nil
}
}

12 changes: 11 additions & 1 deletion gneto.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,17 @@ func init() {
continue
}
c.URL = pc.URL
c.Cert, err = tls.X509KeyPair([]byte(pc.CertPEM), []byte(pc.KeyPEM))
certPEM, err := loadCertificate(pc.CertPEM)
if err != nil {
log.Printf("init: failed to read certificate from %s: %v", pc.CertPEM, err)
continue
}
keyPEM, err := loadCertificate(pc.KeyPEM)
if err != nil {
log.Printf("init: failed to read certificate private key from %s: %v", pc.KeyPEM, err)
continue
}
c.Cert, err = tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
log.Printf("init: failed to parse client certificate PEM data for %s: %v", c.URL, err)
continue
Expand Down
4 changes: 2 additions & 2 deletions sample-client-certs.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
{
"url": "gemini://example.com/foo/bar/",
"certPEM": "-----BEGIN CERTIFICATE-----\nMIIDfzCCAmegAwIBAgIUAgQAyx0G0Pn6gIH5cZQFuqs7DgMwDQYJKoZIhvcNAQEL\nBQAwTzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxEzARBgNVBAoM\nCk9yZyBuYW1lIDQxFjAUBgNVBAMMDUNvbW1vbiBuYW1lIDQwHhcNMjAxMjMwMjI1\nMjA3WhcNMjExMjMwMjI1MjA3WjBPMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t\nZS1TdGF0ZTETMBEGA1UECgwKT3JnIG5hbWUgNDEWMBQGA1UEAwwNQ29tbW9uIG5h\nbWUgNDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMHQb1ssymqUa8ud\nOLWspoz3E5UBHnIQwecz+pQZJE9G4eGDMN+ryj4r/NqMb7cwLEjSixk4is/ElVL8\nYPnreTlls+AJD1kvmaACrabgDh18WErIVpJT4MIMk25LXdcmUzKlBubwiAPcteRx\ntXvwZhHvdK38SCx+LpbkTvk+v08uuThRyt/su2ryx0RZDBDxYvUBBgYYnDCswxgA\n0IiL6Mcg7dySC/VP8w7Vd3qeu2L4/PRRmZpk9BldaXy84r+ZMuuA3KagFl0nn3NK\nn0G9oN+NXqrv9wcBd/1LboD1TPzYZAoy5obZlGRkudaBCT41x/MdGQteJykAW81H\noe//n58CAwEAAaNTMFEwHQYDVR0OBBYEFMbsTI6LWo3CDHc+8W23vY+8JlPLMB8G\nA1UdIwQYMBaAFMbsTI6LWo3CDHc+8W23vY+8JlPLMA8GA1UdEwEB/wQFMAMBAf8w\nDQYJKoZIhvcNAQELBQADggEBACk/oXfdg6arJB9DD0BbUu2m6fwvLoQBSZGfIYJ7\nkRnlpy30gFZw+fh5aygnG2JEB4iJ42VS8kAsjMo1QJ6G/HdfQCsK2GpeTfSR/FzF\n6w6gTfpBtmpxZ4x8697n93pw7RRNAMcE796/uIAEI1CTJhdyy95a4yS5qO+8k2tz\nCFvITWBeY0gKhooOxTGsTe56iTSW7bu/IYsumNnK8LydgEhF5bSgidlY8scdNIGF\nPl4vQMOSner5GV92QTigMgto+V6gCIKZ/ocJytMzsZjQaU9HYWKW9w0aO8+MJtfw\n7hkt6tM6gmvQJPa6B3tgLWIZYIAukPFP2Uw6nTFCybgRxlg=\n-----END CERTIFICATE-----",
"keyPEM": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDB0G9bLMpqlGvL\nnTi1rKaM9xOVAR5yEMHnM/qUGSRPRuHhgzDfq8o+K/zajG+3MCxI0osZOIrPxJVS\n/GD563k5ZbPgCQ9ZL5mgAq2m4A4dfFhKyFaSU+DCDJNuS13XJlMypQbm8IgD3LXk\ncbV78GYR73St/Egsfi6W5E75Pr9PLrk4Ucrf7Ltq8sdEWQwQ8WL1AQYGGJwwrMMY\nANCIi+jHIO3ckgv1T/MO1Xd6nrti+Pz0UZmaZPQZXWl8vOK/mTLrgNymoBZdJ59z\nSp9BvaDfjV6q7/cHAXf9S26A9Uz82GQKMuaG2ZRkZLnWgQk+NcfzHRkLXicpAFvN\nR6Hv/5+fAgMBAAECggEAT3jhgHhgU82iWe6RB2XRMXJK1EmOK2WVrPFSaZHZoqxF\nCQybaMvvdQjieNcnI+2b6wxyPxhBSyqntEyKk1Ar+A4s8MumQILVMpiGjivHfe2z\n4o49eWjte4Rem9ZJl2Q+r0CeEOpGS5cf+plpunV71RTkOkd9bMkc34CkpW1GUvf1\nXwxXbA+6nvCf3AsJg99ML1evBMih3qE7G4RxQvcN5GCAs5ik2vg/2tPZ9Bz3D1aL\nA0z1WkT15ully2lp2UMMhXelKNp33TLcNEad9zNPsVyP/1HGVOu8OFTT+kduwbks\ndzp2l+l2l9U7z3ovYRtSwNYvenCqe0I4iW8SVMuOWQKBgQDyw3nBbwgS6wgQNqH6\ntqrV+BWcJh9hRyvSVa2tTuJgom6VTGA63kCAXMBQP5NeDMgdT8POs9LhuwSJjsTm\n1oam8CxafMBA56g7Yk8v1vmusQLc3sTmgM1aJCSz6nuqAqii4juY2WLxqHuPtA+K\nXPuaZY3TNdqYJteTrjefQDJgKwKBgQDMYbfEUHu6qPG6cra9Ewye7e0sKL0afd17\nOeJNAPCPqj3xhqVdyZxQoP7JoCqvdb7qsdzE0hrqT8wz6kewIcOuQw+94Q8WQB1r\nLmHK/ElQqqqKX1A/vUsheiUncZXfSWhn0wLhK2jzfE4vTPCut9G+GAZeEo6XP9hJ\nWUgL3xAQXQKBgFUawBFW2k6/hGkirfBVn1g5i2HdX3zb1Xn8PVGXaPcVmozOZKHe\njmAxo92+G+yJsJHOB8fr9I7b4EBVA6QlKrlVU0c5mrBmRezjjv0ncQqT1XwWwJJK\nLzNdnlxQZJ/6JKJNizUPaIdtWDvNlPEdnbrHxUt5ArP6UfLczXUPrVlXAoGBAI/s\nCAJAQsDRE1geS7ydW3fXR/qevXuYQozx2AAttzkTwwb/sBd5T5AfrwvAtA5WthiD\nI1meMsHpa3zrb4wCWs+t/bnScFNU1uKRCOBuBBq/89P5BoO8AtoSL3O1MrrH8LOc\nDh0N+pvrXwtD/QCsBRD9zg4Ut0Ce/um361ogvCkpAoGAca3QwbHO/8x45sM8UwCf\nErHcAfRHZgJbl5fugpyAjM4/Gm8jK1y2ShB0CKcfQGNwfNoNRXiRw1FZ6ExgCQhZ\nELUQt+1txpQai0wcylOumrx2GWrqSCEyQZLGmifDZ4v+bIYteSh2ymP1eHDBl3HJ\n1lI8cht4BYtPNrCnuYlFES8=\n-----END PRIVATE KEY-----"
"certPEM": "~/.local/share/certificates/example.com.crt",
"keyPEM": "~/.local/share/certificates/example.com.key"
}
]