mirror of
https://github.com/square/certigo.git
synced 2024-04-21 12:32:40 +00:00
128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
/*-
|
|
* Copyright 2016 Square 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.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
)
|
|
|
|
type simpleVerifyCert struct {
|
|
Name string `json:"name"`
|
|
IsSelfSigned bool `json:"is_self_signed"`
|
|
SignatureAlgorithm simpleSigAlg `json:"signature_algorithm"`
|
|
}
|
|
|
|
type simpleVerification struct {
|
|
Error string `json:"error,omitempty"`
|
|
Chains [][]simpleVerifyCert `json:"chains"`
|
|
}
|
|
|
|
func caBundle(caPath string) *x509.CertPool {
|
|
if caPath == "" {
|
|
return nil
|
|
}
|
|
|
|
bundleBytes, err := ioutil.ReadFile(caPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "error reading CA bundle: %s\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
bundle := x509.NewCertPool()
|
|
bundle.AppendCertsFromPEM(bundleBytes)
|
|
return bundle
|
|
}
|
|
|
|
func verifyChain(certs []*x509.Certificate, dnsName, caPath string) simpleVerification {
|
|
result := simpleVerification{
|
|
Chains: [][]simpleVerifyCert{},
|
|
}
|
|
|
|
intermediates := x509.NewCertPool()
|
|
for i := 1; i < len(certs); i++ {
|
|
intermediates.AddCert(certs[i])
|
|
}
|
|
|
|
opts := x509.VerifyOptions{
|
|
DNSName: dnsName,
|
|
Roots: caBundle(caPath),
|
|
Intermediates: intermediates,
|
|
}
|
|
|
|
chains, err := certs[0].Verify(opts)
|
|
if err != nil {
|
|
result.Error = fmt.Sprintf("%s", err)
|
|
return result
|
|
}
|
|
|
|
//green.Printf("Server certificates appear to be valid (found %d chains):\n", len(chains))
|
|
for _, chain := range chains {
|
|
aChain := []simpleVerifyCert{}
|
|
for _, cert := range chain {
|
|
aCert := simpleVerifyCert{}
|
|
if cert.Subject.CommonName != "" {
|
|
aCert.Name = cert.Subject.CommonName
|
|
} else {
|
|
aCert.Name = fmt.Sprintf("Serial #%s", cert.SerialNumber.String())
|
|
}
|
|
aCert.IsSelfSigned = isSelfSigned(cert)
|
|
aCert.SignatureAlgorithm = simpleSigAlg(cert.SignatureAlgorithm)
|
|
aChain = append(aChain, aCert)
|
|
}
|
|
result.Chains = append(result.Chains, aChain)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func fmtCert(cert simpleVerifyCert) string {
|
|
name := cert.Name
|
|
if cert.IsSelfSigned {
|
|
name += green.SprintfFunc()(" [self-signed]")
|
|
}
|
|
for _, alg := range badSignatureAlgorithms {
|
|
if x509.SignatureAlgorithm(cert.SignatureAlgorithm) == alg {
|
|
name += red.SprintfFunc()(" [%s]", algString(alg))
|
|
break
|
|
}
|
|
}
|
|
return name
|
|
}
|
|
|
|
func printVerifyResult(result simpleVerification) {
|
|
if result.Error != "" {
|
|
red.Printf("Failed to verify certificate chain:\n")
|
|
fmt.Printf("\t%s\n", result.Error)
|
|
return
|
|
}
|
|
for i, chain := range result.Chains {
|
|
fmt.Printf("[%d] %s\n", i, fmtCert(chain[0]))
|
|
for j, cert := range chain {
|
|
if j == 0 {
|
|
continue
|
|
}
|
|
fmt.Printf("\t=> %s\n", fmtCert(cert))
|
|
}
|
|
}
|
|
}
|
|
|
|
func isSelfSigned(cert *x509.Certificate) bool {
|
|
return cert.CheckSignatureFrom(cert) == nil
|
|
}
|