Merge pull request #168 from square/cs/go-1.11

Use Go 1.11, use built-in functions for URI names
This commit is contained in:
Cedric Staub
2018-10-23 14:45:43 -07:00
committed by GitHub
16 changed files with 4 additions and 444 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
language: go
go:
- '1.10.x'
- '1.11.x'
install:
- go get github.com/Masterminds/glide
Generated
-2
View File
@@ -27,8 +27,6 @@ imports:
version: 6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c
- name: github.com/mwitkow/go-http-dialer
version: 378f744fb2b81a6b96e3f40cde4f3bcab5a9cff0
- name: github.com/spiffe/go-spiffe
version: 2bb3101d62b4bea6371d792e818360e3f056867b
- name: golang.org/x/crypto
version: b2aa35443fbc700ab74c586ae79b81c171851023
subpackages:
-1
View File
@@ -12,5 +12,4 @@ import:
version: ^1.2.0
- package: github.com/Masterminds/sprig
version: ^2.12.0
- package: github.com/spiffe/go-spiffe
- package: github.com/mwitkow/go-http-dialer
+3 -6
View File
@@ -32,8 +32,6 @@ import (
"strconv"
"strings"
"time"
"github.com/spiffe/go-spiffe/uri"
)
var keyUsages = []x509.KeyUsage{
@@ -244,12 +242,11 @@ func createSimpleCertificate(name string, cert *x509.Certificate) simpleCertific
PEM: string(pem.EncodeToMemory(EncodeX509ToPEM(cert, nil))),
}
uriNames, err := uri.GetURINamesFromCertificate(cert)
if err == nil {
out.URINames = uriNames
for _, uri := range cert.URIs {
out.URINames = append(out.URINames, uri.String())
}
out.Warnings = certWarnings(cert, uriNames)
out.Warnings = certWarnings(cert, out.URINames)
if cert.BasicConstraintsValid {
out.BasicConstraints = &basicConstraints{
-12
View File
@@ -1,12 +0,0 @@
version: 2
jobs:
build:
machine: true
working_directory: ~
steps:
- checkout
- run: make test
-1
View File
@@ -1 +0,0 @@
* @amartinezfayo @evan2645
-13
View File
@@ -1,13 +0,0 @@
Copyright 2017 The SPIFFE Project & Scytale, Inc
Licensed 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.
-12
View File
@@ -1,12 +0,0 @@
ROOT := github.com/spiffe/go-spiffe
PACKAGE_LIST := uri spiffe
test: vet
@for p in $(PACKAGE_LIST); do \
go test $(ROOT)/$$p || exit 1; \
done
vet:
@for p in $(PACKAGE_LIST); do \
go vet $(ROOT)/$$p; \
done
-28
View File
@@ -1,28 +0,0 @@
# go-spiffe library [![GoDoc](https://godoc.org/github.com/spiffe/go-spiffe?status.svg)](https://godoc.org/github.com/spiffe/go-spiffe)
## Overview
The go-spiffe library provides functionality to parse and verify SPIFFE
identities encoded in X.509 certificates as described in the
[SPIFFE Standards](https://github.com/spiffe/spiffe/tree/master/standards).
## Installing it
```shell
go get -u -v github.com/spiffe/go-spiffe
```
## Importing it in your Go code
See examples in [examples_test.go](./example_test.go)
or visit the [GoDoc](https://godoc.org/github.com/spiffe/go-spiffe) for more information
## Installing the command line interface
The command line interface can be used to retrieve and view URIs stored
in the SAN extension of certificates
```shell
go get -u -v github.com/spiffe/go-spiffe/cmd/spiffe
spiffe testdata/leaf.cert.pem $HOME/certs/proj.pem
Path:: #1: "testdata/leaf.cert.pem"
URI #1: "spiffe://dev.acme.com/path/service"
```
-49
View File
@@ -1,49 +0,0 @@
package main
import (
"log"
"os"
spiffe "github.com/spiffe/go-spiffe"
)
func main() {
// Make log not print out time information
log.SetFlags(0)
if len(os.Args) <= 1 {
log.Fatalf("\033[31mexpecting path [paths...] e.g\033[00m\n\tspiffe /var/lib/letsencrypt/spiffe.pem $HOME/Desktop/certs/cert.pem\033[00m\n")
}
seenPaths := make(map[string]bool)
args := os.Args[1:]
for i, path := range args {
if _, seen := seenPaths[path]; seen {
continue
}
seenPaths[path] = true
f, err := os.Open(path)
if err != nil {
log.Printf("\n#%d: err=%v\n", i, err)
continue
}
uris, err := spiffe.FGetURINamesFromPEM(f)
_ = f.Close()
if err != nil {
log.Printf("\n#%d: parseErr=%v\n", i, err)
continue
}
if len(uris) == 0 {
log.Printf("\n#%d: no uris could be parsed\n", i)
continue
}
log.Printf("Path:: #%d: %q\n", i+1, path)
for j, uri := range uris {
log.Printf("\tURI #%d: %q\n", j+1, uri)
}
}
}
-38
View File
@@ -1,38 +0,0 @@
package spiffe
import (
"crypto/x509"
"fmt"
"github.com/spiffe/go-spiffe/uri"
)
// Tries to match a SPIFFE ID, given a certificate
func MatchID(ids []string, cert *x509.Certificate) error {
parsedIDs, err := uri.GetURINamesFromCertificate(cert)
if err != nil {
return err
}
for _, parsedID := range parsedIDs {
for _, id := range ids {
if parsedID == id {
return nil
}
}
}
return fmt.Errorf("SPIFFE ID mismatch")
}
// Verify a SPIFFE certificate and its certification path
func VerifyCertificate(leaf *x509.Certificate, intermediates *x509.CertPool, roots *x509.CertPool) error {
verifyOpts := x509.VerifyOptions{
Intermediates: intermediates,
Roots: roots,
}
// TODO: SPIFFE-specific validation of leaf and verified chain
_, err := leaf.Verify(verifyOpts)
return err
}
-32
View File
@@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFiDCCA3CgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwNzELMAkGA1UEBhMCVVMx
FzAVBgNVBAoMDnRlc3QxLmFjbWUuY29tMQ8wDQYDVQQDDAZSb290Q0EwHhcNMTcw
NzE5MTY1MDIwWhcNMTcxMDI3MTY1MDIwWjA/MQswCQYDVQQGEwJVUzEXMBUGA1UE
CgwOdGVzdDEuYWNtZS5jb20xFzAVBgNVBAMMDkludGVybWVkaWFldENBMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAph7QhbUKEjMWu2R/WXIc8RR0ymCL
njJTm0D5duTe7V2hklLhCo1KnZAjvDiDX9r85UfEja5MYItHmFF4HOZjSG6nY3Yg
Mm5hdJM7Jmv9NJR8DJInROabfRcaPdugs2UQ41jCEygIoWiZ9+yVlZ21MNW0yQdI
JHUNndQfXpS7dBdKw6fUqzZgpdzo86mAapZDIPL7gXv6MW8JhbvQCm+bg7SRIJOD
t/a1T0nHPNuwxdDWjGcmJEQRknffL8pheDlW9sMAd/4BtIeaWUEb3JjdDoaJ9SWU
tCgGRZOMnmry8npJnssyoLUtIPuk8949REOUB15nT94EhTtb1BMdiuD8P8HOHWC6
mcxpJCsKlCFmOQpES6WROqjckQJ0f/xPOdKAdI9W0Eg3TRtibV9XTfTvv8SPug9/
6FnkdpwF5xlJ/XcuW8GtpHUZNQ0NyxjUh2rQRAbwdTMeCvhx5fPHpT2kc6PIlzLw
h4Pt0Xvc1cNt2iJOVDqs75HvvUe4RYTfdqlK5385u/s2cxQrLuB4owJrTyrqc3yM
L/0h5JXr9P+T+axrd5WQWz2ngiaimli2vxZTR++RfBnyCgQGTiY+9UUOYYgHh6hJ
CGUPY77DsKuTfIXYlra+c65FKFAcZrC4vt1CLtBqW2mBy7U868c0L9PZ1g3+WGvA
FmnZA6MgUKQE0i0CAwEAAaOBlTCBkjAdBgNVHQ4EFgQUNd238edKw2Tt8tgmXRz4
JXhVBKAwHwYDVR0jBBgwFoAUUeBRd0yew4JtInksRTlbz71YwtEwDwYDVR0TAQH/
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwLwYDVR0eAQH/BCUwI6AhMA+GDS5kZXYu
YWNtZS5jb20wDoYMZGV2LmFjbWUuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQBLljbI
ekm5/uhFbc/aCAlomwGkXFvyMXx7eD7Pimzn4H31nYvQ5ha2M0536JC/mH1xi7nK
OOMuSBAqjpALoRk4+3O5s6r9BN8KKhcI4jDKHqOSBe38K+Ad06B52yxYyL6YmJwk
Zlazf3KvExzUWS0t4ehNuI2HJvvwEitMpOF3hhwAYk3v/x2YBtpglH+yZC4Sfoma
ItjFWeD+DA0bVAMJiErz8Pq91avnC8SPpPXiPJVOaBhaNc8po6x6cwSqY6RnI2/K
0kUWXXH65Pz0JYru53ALzy4ouwJItcgMvzZPGVaojxEbGDrjXEkWIGresFrw1Ijr
IyrQUqWa9wW6ik+IQOb6m3FZYB8jMO7nhop9Ywm9uoSmFRg6RsP2AWHBMYP7lZqw
fx3HjrAvc3ycIZ2tSPkdLd5n8YuL31CVpa9aGwT5dYzIVd/eFUrCUIGV2j8XHgkL
gMPr8JhNPAG0B4rRpEXmK3HHybo3s0M8i80Lit98xzupNpng97xKT7jJBSinNTdt
/2uU7diHQM7aPNmNG+Wu3GXVt/MZuDMSFrh9AHl0A/Y4mNu6KKqRMJuvsfy/j1DD
fDGmAkjHrspiorTruphHk+cymJfjAGqZ0l6il4Wi5w4R5jrxnJMhkxbjr/PG5xCS
+ZKPPNZbpPIY54oQ2bHkuaQgzJ7us4ZW7gxgbw==
-----END CERTIFICATE-----
-28
View File
@@ -1,28 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIE1DCCArygAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzELMAkGA1UEBhMCVVMx
FzAVBgNVBAoMDnRlc3QxLmFjbWUuY29tMRcwFQYDVQQDDA5JbnRlcm1lZGlhZXRD
QTAeFw0xNzA3MTkxNjUwMjBaFw0xNzA3MjkxNjUwMjBaMDUxCzAJBgNVBAYTAlVT
MRcwFQYDVQQKDA50ZXN0MS5hY21lLmNvbTENMAsGA1UEAwwEYmxvZzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKm8P47lABp4+rz2nN+QYrxedbaFVWoF
FuoSkqcHsafMwbMrN+kI6wJVtlbwviDvxWFJ92q0H71QNFybTsmof3KUN/kYCp7P
+LKhBrN0ttWI5q6v5eDrjN0VdtVdnlZOYmJFbvETOgfK/qXKNRRM8HYW0tdqrtEw
CR5dIu53xVUSViBdwXpuy2c5W2mFn1gxTpdW+3hbZsL1pHrU9qPWLtTgl/KY8kjs
I7KW1cIcinE4SJomhB5L/4emhxKGY+kEa2+fN9IPjjvKSMOw9kiBKk1GHZcIY5EA
O3TIfUk3fysPzi5qA0su/bNtPQy1uXgXS10xUlV7pqRPvHjiNzgFkXUCAwEAAaOB
4zCB4DAJBgNVHRMEAjAAMB0GA1UdDgQWBBRVQ91jSOONzVr1VGBdJOlPN+3XxTBg
BgNVHSMEWTBXgBQ13bfx50rDZO3y2CZdHPgleFUEoKE7pDkwNzELMAkGA1UEBhMC
VVMxFzAVBgNVBAoMDnRlc3QxLmFjbWUuY29tMQ8wDQYDVQQDDAZSb290Q0GCAhAA
MA4GA1UdDwEB/wQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAtBgNVHREEJjAk
hiJzcGlmZmU6Ly9kZXYuYWNtZS5jb20vcGF0aC9zZXJ2aWNlMA0GCSqGSIb3DQEB
CwUAA4ICAQBp2+rtUxt1VmNM/vi6PwoSoYzWFmQ2nc4OM7bsOG4uppU54wRYZ+T7
c42EcrpyBgWn+rWHT1Hi6SNcmloKHydaUTZ4pq3IlKKnBNqwivU5BzIxYLDrhR/U
wd9s1tgmLvADqkQa1XjjSFn5Auoj1R640ry4qpw8IOusdm6wVhru4ssRnHX4E2uR
jQe7b3ws38aZhjtL78Ip0BB4yPxWJRp/WmEoT33QP+cZhA4IYWECxNODr6DSJeq2
VNu/6JACGrNfM2Sjt4Wxz+nIa3cKDNCA6PR8StTUTcoQ6ZBzpn+n/Q1xSRIOJz6N
hgfkyb9O7HAMdAP+TxehjqG3gh5Ky2DgYMCIZOztVzsuOb1DGJe/kGUKeRJLl2/O
QwkctwUOcVIxckNu6OvclriFzvoXObqO77XeCI2V1Vef0wGTWlWNOdbFa4708Y7f
5UdwInYQUi87RFDnc1SDU4Jrsv4KzZiv9FCfDg8pCBIdWpWT7DAuI0d7i7PZ+iFt
ZZ6sb/YDkyiDXU4ar/dja0FDE2r7jsN9D+FfW49+iDvXr4ELQyhZpW3Zr1Ojwm58
CJzjZwbRYiVwPBRsKmiYfO1E7esvw3CmjK5chfz8c40f6/APDro9ZmYNBRv2CnJy
t/DtcM/GpAhBbLP9Tk7kPB41v5fRIxVDo50Iz/qvkr37pQ4RsejSFg==
-----END CERTIFICATE-----
-70
View File
@@ -1,70 +0,0 @@
package tls
import (
"crypto/tls"
"crypto/x509"
"github.com/spiffe/go-spiffe/spiffe"
)
type TLSPeer struct {
// Slice of permitted SPIFFE IDs
SpiffeIDs []string
TrustRoots *x509.CertPool
}
// NewTLSConfig creates a SPIFFE-compatible TLS configuration.
// We are opinionated towards mutual TLS. If you don't want
// mutual TLS, you'll need to update the returned config.
//
// `certs` contains one or more certificates to present to the
// other side of the connection, leaf first.
func (t *TLSPeer) NewTLSConfig(certs []tls.Certificate) *tls.Config {
config := &tls.Config{
// Disable validation/verification because we perform
// this step with custom logic in `verifyPeerCertificate`
ClientAuth: tls.RequireAnyClientCert,
InsecureSkipVerify: true,
VerifyPeerCertificate: t.verifyPeerCertificate,
Certificates: certs,
}
return config
}
// verifyPeerCertificate serves callbacks from TLS listeners/dialers. It performs
// SPIFFE-specific validation steps on behalf of the golang TLS library
func (t *TLSPeer) verifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) (err error) {
// First, parse all received certs
var certs []*x509.Certificate
for _, rawCert := range rawCerts {
cert, err := x509.ParseCertificate(rawCert)
if err != nil {
return err
}
certs = append(certs, cert)
}
// Perform path validation
// Leaf is the first off the wire:
// https://tools.ietf.org/html/rfc5246#section-7.4.2
intermediates := x509.NewCertPool()
for _, intermediate := range certs[1:] {
intermediates.AddCert(intermediate)
}
err = spiffe.VerifyCertificate(certs[0], intermediates, t.TrustRoots)
if err != nil {
return err
}
// Look for a known SPIFFE ID in the leaf
err = spiffe.MatchID(t.SpiffeIDs, certs[0])
if err != nil {
return err
}
// If we are here, then all is well
return nil
}
-29
View File
@@ -1,29 +0,0 @@
package uri
import(
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
)
var OidExtensionSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17}
var OidExtensionKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 15}
// GetExtensionsFromAsn1ObjectIdentifier takes a parsed X.509 certificate and an OID
// and gets the extensions that match the given OID
func GetExtensionsFromAsn1ObjectIdentifier(certificate *x509.Certificate, id asn1.ObjectIdentifier) []pkix.Extension {
var extensions []pkix.Extension
for _, extension := range certificate.Extensions {
if extension.Id.Equal(id) {
extensions = append(extensions, extension)
}
}
return extensions
}
// GetKeyUsageExtensionsFromCertificate takes a parsed X.509 certificate and gets the Key Usage extensions
func GetKeyUsageExtensionsFromCertificate(cert *x509.Certificate) (extension []pkix.Extension) {
return GetExtensionsFromAsn1ObjectIdentifier(cert, OidExtensionKeyUsage)
}
-122
View File
@@ -1,122 +0,0 @@
package uri
import (
"encoding/asn1"
"errors"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"io"
"io/ioutil"
)
func getURINamesFromSANExtension(sanExtension []byte) (uris []string, 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(sanExtension, &seq); err != nil {
return uris, err
} else if len(rest) != 0 {
err = errors.New("x509: trailing data after X.509 extension")
return uris, err
}
if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
err = asn1.StructuralError{Msg: "bad SAN sequence"}
return uris, err
}
rest = seq.Bytes
for len(rest) > 0 {
var v asn1.RawValue
rest, err = asn1.Unmarshal(rest, &v)
if err != nil {
return uris, err
}
if v.Tag == 6 {
uris = append(uris, string(v.Bytes))
}
}
return uris, err
}
// GetURINamesFromCertificate takes a parsed X.509 certificate and gets the URIs from the SAN extension.
func GetURINamesFromCertificate(cert *x509.Certificate) (uris []string, err error) {
for _, ext := range GetExtensionsFromAsn1ObjectIdentifier(cert, OidExtensionSubjectAltName) {
uris, err = getURINamesFromSANExtension(ext.Value)
if err != nil {
return uris, err
}
}
return uris, nil
}
// GetURINamesFromPEM parses a PEM-encoded X.509 certificate and gets the URIs from the SAN extension.
func GetURINamesFromPEM(encodedCertificate string) (uris []string, err error) {
return uriNamesFromPEM([]byte(encodedCertificate))
}
func uriNamesFromPEM(encodedCertificate []byte) (uris []string, err error) {
block, _ := pem.Decode(encodedCertificate)
if block == nil {
return uris, errors.New("failed to decode certificate PEM")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return uris, errors.New("failed to parse certificate: " + err.Error())
}
return GetURINamesFromCertificate(cert)
}
// FGetURINamesFromPEM retrieves URIs from the SAN extension of a
// PEM-encoded X.509 certificate, whose content is in the provided io.Reader.
func FGetURINamesFromPEM(f io.Reader) (uris []string, err error) {
blob, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
return uriNamesFromPEM(blob)
}
// GetURINamesFromExtensions retrieves URIs from the SAN extension of a slice of extensions
func GetURINamesFromExtensions(extensions *[]pkix.Extension) (uris []string, err error) {
for _, ext := range *extensions {
if ext.Id.Equal(OidExtensionSubjectAltName) {
uris, err = getURINamesFromSANExtension(ext.Value)
if err != nil {
return uris, err
}
}
}
return uris, nil
}
// MarshalUriSANs takes URI strings and returns the ASN.1 structure to be used
// in the Value field for the SAN Extension
func MarshalUriSANs(uris []string) (derBytes []byte, err error) {
var rawValues []asn1.RawValue
for _, name := range uris {
rawValues = append(rawValues, asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)})
}
return asn1.Marshal(rawValues)
}