Add support for SubjectAltName in SSL certificates
This commit is contained in:
parent
9ec862bb78
commit
4ee2bdc302
1 changed files with 84 additions and 0 deletions
|
@ -23,13 +23,16 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
@ -37,6 +40,10 @@ import (
|
||||||
"k8s.io/ingress/core/pkg/ingress"
|
"k8s.io/ingress/core/pkg/ingress"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
oidExtensionSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17}
|
||||||
|
)
|
||||||
|
|
||||||
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
|
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
|
||||||
func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert, error) {
|
func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert, error) {
|
||||||
pemName := fmt.Sprintf("%v.pem", name)
|
pemName := fmt.Sprintf("%v.pem", name)
|
||||||
|
@ -102,6 +109,17 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
|
||||||
cn = append(cn, pemCert.DNSNames...)
|
cn = append(cn, pemCert.DNSNames...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(pemCert.Extensions) > 0 {
|
||||||
|
for _, ext := range getExtension(pemCert, oidExtensionSubjectAltName) {
|
||||||
|
dns, _, _, err := parseSANExtension(ext.Value)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("unexpected error parsing certificate extensions: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cn = append(cn, dns...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = os.Rename(tempPemFile.Name(), pemFileName)
|
err = os.Rename(tempPemFile.Name(), pemFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not move temp pem file %v to destination %v: %v", tempPemFile.Name(), pemFileName, err)
|
return nil, fmt.Errorf("could not move temp pem file %v to destination %v: %v", tempPemFile.Name(), pemFileName, err)
|
||||||
|
@ -150,6 +168,72 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getExtension(c *x509.Certificate, id asn1.ObjectIdentifier) []pkix.Extension {
|
||||||
|
var exts []pkix.Extension
|
||||||
|
for _, ext := range c.Extensions {
|
||||||
|
if ext.Id.Equal(id) {
|
||||||
|
exts = append(exts, ext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exts
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) {
|
||||||
|
// RFC 5280, 4.2.1.6
|
||||||
|
|
||||||
|
// SubjectAltName ::= GeneralNames
|
||||||
|
//
|
||||||
|
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
|
||||||
|
//
|
||||||
|
// GeneralName ::= CHOICE {
|
||||||
|
// otherName [0] OtherName,
|
||||||
|
// rfc822Name [1] IA5String,
|
||||||
|
// dNSName [2] IA5String,
|
||||||
|
// x400Address [3] ORAddress,
|
||||||
|
// directoryName [4] Name,
|
||||||
|
// ediPartyName [5] EDIPartyName,
|
||||||
|
// uniformResourceIdentifier [6] IA5String,
|
||||||
|
// iPAddress [7] OCTET STRING,
|
||||||
|
// registeredID [8] OBJECT IDENTIFIER }
|
||||||
|
var seq asn1.RawValue
|
||||||
|
var rest []byte
|
||||||
|
if rest, err = asn1.Unmarshal(value, &seq); err != nil {
|
||||||
|
return
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
err = errors.New("x509: trailing data after X.509 extension")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
|
||||||
|
err = asn1.StructuralError{Msg: "bad SAN sequence"}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rest = seq.Bytes
|
||||||
|
for len(rest) > 0 {
|
||||||
|
var v asn1.RawValue
|
||||||
|
rest, err = asn1.Unmarshal(rest, &v)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch v.Tag {
|
||||||
|
case 1:
|
||||||
|
emailAddresses = append(emailAddresses, string(v.Bytes))
|
||||||
|
case 2:
|
||||||
|
dnsNames = append(dnsNames, string(v.Bytes))
|
||||||
|
case 7:
|
||||||
|
switch len(v.Bytes) {
|
||||||
|
case net.IPv4len, net.IPv6len:
|
||||||
|
ipAddresses = append(ipAddresses, v.Bytes)
|
||||||
|
default:
|
||||||
|
err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// AddCertAuth creates a .pem file with the specified CAs to be used in Cert Authentication
|
// AddCertAuth creates a .pem file with the specified CAs to be used in Cert Authentication
|
||||||
// If it's already exists, it's clobbered.
|
// If it's already exists, it's clobbered.
|
||||||
func AddCertAuth(name string, ca []byte) (*ingress.SSLCert, error) {
|
func AddCertAuth(name string, ca []byte) (*ingress.SSLCert, error) {
|
||||||
|
|
Loading…
Reference in a new issue