Merge pull request #146 from square/cs/stuff2

Shell completion & URI names display
This commit is contained in:
Cedric Staub
2017-08-07 16:01:15 -07:00
committed by GitHub
16 changed files with 264 additions and 12 deletions
+3 -1
View File
@@ -1,2 +1,4 @@
certigo
certigo.exe
certigo.exe
man/
shell/
+5
View File
@@ -17,3 +17,8 @@ go build -o bin/certigo ${REPO_PATH}
# Generate man page
mkdir -p man
bin/certigo --help-man > man/certigo.1
# Generate completion scripts
mkdir -p shell
bin/certigo --completion-script-zsh > shell/certigo.completion.zsh
bin/certigo --completion-script-bash > shell/certigo.completion.bash
Generated
+4 -2
View File
@@ -1,5 +1,5 @@
hash: f13313281515b6941a7f67c8dc051c6cd76314f3708fe93d1f701278856cfc1a
updated: 2017-08-02T15:41:22.000418583-07:00
hash: f7ccb11674e8a2d85c7cdc160a5dd7a3160b1280f9443879235148659939ffb5
updated: 2017-08-07T15:26:47.237893811-07:00
imports:
- name: github.com/alecthomas/template
version: a0175ee3bccc567396460bf5acd36800cb10c49c
@@ -27,6 +27,8 @@ imports:
repo: https://github.com/mattn/go-isatty
- name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/spiffe/go-spiffe
version: 2a3d812e4ae000302a242cb42490ff395e9508de
- name: golang.org/x/crypto
version: 5bcd134fee4dd1475da17714aac19c0aa0142e2f
subpackages:
+1
View File
@@ -12,3 +12,4 @@ import:
version: ^1.2.0
- package: github.com/Masterminds/sprig
version: ^2.12.0
- package: github.com/spiffe/go-spiffe
+10 -4
View File
@@ -58,11 +58,14 @@ Key Usage:{{range .KeyUsage | keyUsage}}
Extended Key Usage:{{range .ExtKeyUsage}}
{{. | extKeyUsage}}{{end}}{{end}}
{{- if .AltDNSNames}}
Alternate DNS Names:
DNS Names:
{{wrapWith .Width "\n\t" (join ", " .AltDNSNames)}}{{end}}
{{- if .AltIPAddresses}}
Alternate IP Addresses:
IP Addresses:
{{wrapWith .Width "\n\t" (join ", " .AltIPAddresses)}}{{end}}
{{- if .URINames}}
URI Names:
{{wrapWith .Width "\n\t" (join ", " .URINames)}}{{end}}
{{- if .EmailAddresses}}
Email Addresses:
{{wrapWith .Width "\n\t" (join ", " .EmailAddresses)}}{{end}}
@@ -80,11 +83,14 @@ Issuer: {{.Issuer.Name | printShortName }}
Name Constraints{{if .PermittedDNSDomains.Critical}} (critical){{end}}: {{range .NameConstraints.PermittedDNSDomains}}
{{.}}{{end}}{{end}}
{{- if .AltDNSNames}}
Alternate DNS Names:
DNS Names:
{{wrapWith .Width "\n\t" (join ", " .AltDNSNames)}}{{end}}
{{- if .AltIPAddresses}}
Alternate IP Addresses:
IP Addresses:
{{wrapWith .Width "\n\t" (join ", " .AltIPAddresses)}}{{end}}
{{- if .URINames}}
URI Names:
{{wrapWith .Width "\n\t" (join ", " .URINames)}}{{end}}
{{- if .EmailAddresses}}
Email Addresses:
{{wrapWith .Width "\n\t" (join ", " .EmailAddresses)}}{{end}}
+8
View File
@@ -32,6 +32,8 @@ import (
"strconv"
"strings"
"time"
"github.com/spiffe/go-spiffe"
)
var keyUsages = []x509.KeyUsage{
@@ -189,6 +191,7 @@ type simpleCertificate struct {
ExtKeyUsage []simpleExtKeyUsage `json:"extended_key_usage,omitempty"`
AltDNSNames []string `json:"dns_names,omitempty"`
AltIPAddresses []net.IP `json:"ip_addresses,omitempty"`
URINames []string `json:"uri_names,omitempty"`
EmailAddresses []string `json:"email_addresses,omitempty"`
Warnings []string `json:"warnings,omitempty"`
PEM string `json:"pem,omitempty"`
@@ -231,6 +234,11 @@ func createSimpleCertificate(name string, cert *x509.Certificate) simpleCertific
PEM: string(pem.EncodeToMemory(EncodeX509ToPEM(cert, nil))),
}
uriNames, err := spiffe.GetURINamesFromCertificate(cert)
if err != nil {
out.URINames = uriNames
}
if cert.BasicConstraintsValid {
out.BasicConstraints = &basicConstraints{
IsCA: cert.IsCA,
+1 -1
View File
@@ -137,7 +137,7 @@ Dump a live cert chain (squareup-chain.crt)
Extended Key Usage:
\tServer Auth (esc)
\tClient Auth (esc)
Alternate DNS Names:
DNS Names:
\twww.squareup.com, squareup.com, (esc)
\taccount.squareup.com, mkt.com, www.mkt.com, (esc)
\tmarket.squareup.com, gosq.com, www.gosq.com, (esc)
+2 -2
View File
@@ -31,8 +31,8 @@ Dump an example certificate (example-leaf.crt)
Valid: 2016-06-10 22:14 UTC to 2023-04-15 22:14 UTC
Subject: CN=example-leaf
Issuer: CN=example-leaf
Alternate DNS Names:
DNS Names:
\tlocalhost (esc)
Alternate IP Addresses:
IP Addresses:
\t127.0.0.1, ::1 (esc)
+2 -2
View File
@@ -46,8 +46,8 @@ Dump an example certificate (example-leaf.crt)
Extended Key Usage:
\tClient Auth (esc)
\tServer Auth (esc)
Alternate DNS Names:
DNS Names:
\tlocalhost (esc)
Alternate IP Addresses:
IP Addresses:
\t127.0.0.1, ::1 (esc)
+13
View File
@@ -0,0 +1,13 @@
Copyright 2017 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.
+5
View File
@@ -0,0 +1,5 @@
test: vet
go test
vet:
go vet
+11
View File
@@ -0,0 +1,11 @@
# go-spiffe library
### Overview
The go-spiffe library provides functionality to parse and verify SPIFFE identities encoded in X.509 certificates as described in the [SPIFFE Verifiable Identity Document (SVID) Document Specification](https://github.com/spiffe/svid/blob/master/SPECIFICATION.md).
#### func GetUrisInSubjectAltName
```go
func GetUrisInSubjectAltName(certificateString string) (uris []string, err error)
```
Parses an X.509 certificate in PEM format and gets the URIs from the Subject Alternative Name extension.
+95
View File
@@ -0,0 +1,95 @@
package spiffe
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
)
var oidExtensionSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17}
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
} 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
}
if v.Tag == 6 {
uris = append(uris, string(v.Bytes))
}
}
return
}
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
}
// GetUrisInSubjectAltName 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
}
}
return uris, nil
}
// GetUrisInSubjectAltNameEncoded parses a PEM-encoded X.509 certificate and gets the URIs from the SAN extension.
func GetURINamesFromPEM(encodedCertificate string) (uris []string, err error) {
block, _ := pem.Decode([]byte(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)
}
+44
View File
@@ -0,0 +1,44 @@
package spiffe
import (
"io/ioutil"
"testing"
)
func getCertificateFromFile(t *testing.T, certFilePath string) string {
certificateString, err := ioutil.ReadFile(certFilePath)
if err != nil {
t.Fatal(err)
}
return string(certificateString)
}
func TestGetURINamesFromPEM(t *testing.T) {
certPEM := getCertificateFromFile(t, "testdata/leaf.cert.pem")
var golden = "spiffe://dev.acme.com/path/service"
uris, err := GetURINamesFromPEM(string(certPEM))
if err != nil {
t.Error(err)
}
if len(uris) == 1 {
if uris[0] != golden {
t.Fatalf("Expected '%v' but got '%v'", golden, uris[0])
}
} else {
t.Fatalf("Expected 1 URI but got '%v'", len(uris))
}
certPEM = getCertificateFromFile(t, "testdata/intermediate.cert.pem")
uris, err = GetURINamesFromPEM(string(certPEM))
if err == nil {
t.Fatal("Expected to fail")
}
if len(uris) > 0 {
t.Fatalf("Expected to have no URIs but got %v URIs", len(uris))
}
}
+32
View File
@@ -0,0 +1,32 @@
-----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
@@ -0,0 +1,28 @@
-----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-----