github.com/blend/go-sdk@v1.20220411.3/webutil/cert_info.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package webutil 9 10 import ( 11 "crypto/tls" 12 "crypto/x509" 13 "fmt" 14 "net/http" 15 "time" 16 ) 17 18 // ParseCertInfo returns a new cert info from a response from a check. 19 func ParseCertInfo(res *http.Response) *CertInfo { 20 if res == nil || res.TLS == nil || len(res.TLS.PeerCertificates) == 0 { 21 return nil 22 } 23 24 var earliestNotAfter time.Time 25 var latestNotBefore time.Time 26 for _, cert := range res.TLS.PeerCertificates { 27 if earliestNotAfter.IsZero() || earliestNotAfter.After(cert.NotAfter) { 28 earliestNotAfter = cert.NotAfter 29 } 30 if latestNotBefore.IsZero() || latestNotBefore.Before(cert.NotBefore) { 31 latestNotBefore = cert.NotBefore 32 } 33 } 34 35 firstCert := res.TLS.PeerCertificates[0] 36 var issuerNames []string 37 for _, name := range firstCert.Issuer.Names { 38 issuerNames = append(issuerNames, fmt.Sprint(name.Value)) 39 } 40 41 return &CertInfo{ 42 SubjectCommonName: firstCert.Subject.CommonName, 43 IssuerNames: issuerNames, 44 IssuerCommonName: firstCert.Issuer.CommonName, 45 DNSNames: firstCert.DNSNames, 46 NotAfter: earliestNotAfter, 47 NotBefore: latestNotBefore, 48 } 49 } 50 51 // NewCertInfo returns a new cert info. 52 func NewCertInfo(cert *tls.Certificate) (*CertInfo, error) { 53 leaf, err := x509.ParseCertificate(cert.Certificate[0]) 54 if err != nil { 55 return nil, err 56 } 57 var issuerNames []string 58 for _, name := range leaf.Issuer.Names { 59 issuerNames = append(issuerNames, fmt.Sprint(name.Value)) 60 } 61 62 return &CertInfo{ 63 SubjectCommonName: leaf.Subject.CommonName, 64 IssuerNames: issuerNames, 65 IssuerCommonName: leaf.Issuer.CommonName, 66 DNSNames: leaf.DNSNames, 67 NotAfter: leaf.NotAfter, 68 NotBefore: leaf.NotBefore, 69 }, nil 70 } 71 72 // CertInfo is the information for a certificate. 73 type CertInfo struct { 74 SubjectCommonName string `json:"subjectCommonName" yaml:"subjectCommonName"` 75 IssuerCommonName string `json:"issuerCommonName" yaml:"issuerCommonName"` 76 IssuerNames []string `json:"issuerNames" yaml:"issuerNames"` 77 DNSNames []string `json:"dnsNames" yaml:"dnsNames"` 78 NotAfter time.Time `json:"notAfter" yaml:"notAfter"` 79 NotBefore time.Time `json:"notBefore" yaml:"notBefore"` 80 } 81 82 // IsExpired returns if the certificate is strictly expired 83 // and would not be accepted by browsers. 84 func (ci CertInfo) IsExpired() bool { 85 return ci.WillBeExpired(time.Now().UTC()) 86 } 87 88 // WillBeExpired returns if the certificate is strictly expired 89 // and would not be accepted by browsers at a given time. 90 func (ci CertInfo) WillBeExpired(at time.Time) bool { 91 if !ci.NotAfter.IsZero() { 92 if at.UTC().After(ci.NotAfter) { 93 return true 94 } 95 } 96 if !ci.NotBefore.IsZero() { 97 if at.UTC().Before(ci.NotBefore) { 98 return true 99 } 100 } 101 return false 102 }