diff options
author | Niall Sheridan <nsheridan@gmail.com> | 2016-07-31 20:41:52 +0100 |
---|---|---|
committer | Niall Sheridan <nsheridan@gmail.com> | 2016-07-31 21:18:55 +0100 |
commit | 531f63e5a9e82d86a6ee1f5d44bebee0bc51d828 (patch) | |
tree | 882b6dfb10c4db96b9e983fd6112a29d227a416a /vendor/github.com/stripe/krl/parse.go | |
parent | 44fef1c2a163bdfd781ef08a06e3cf5cf9b7d5da (diff) |
Use a KRL for revoked certs
Diffstat (limited to 'vendor/github.com/stripe/krl/parse.go')
-rw-r--r-- | vendor/github.com/stripe/krl/parse.go | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/vendor/github.com/stripe/krl/parse.go b/vendor/github.com/stripe/krl/parse.go new file mode 100644 index 0000000..75f2551 --- /dev/null +++ b/vendor/github.com/stripe/krl/parse.go @@ -0,0 +1,237 @@ +package krl + +import ( + "crypto/sha1" + "fmt" + + "golang.org/x/crypto/ssh" +) + +// Hundreds of millions, or 32MB of bitmap +const krlMaxBitmapSize = 0x10000000 + +// KRLSigningErrors is a slice of error messages which correspond one-to-one +// with KRL.SigningKeys. +type KRLSigningErrors []error + +func (k KRLSigningErrors) Error() string { + return fmt.Sprintf("krl: bad signatures: %v", []error(k)) +} + +func (k KRLSigningErrors) err() error { + for _, err := range k { + if err != nil { + return k + } + } + return nil +} + +// ParseKRL parses a KRL. If the KRL was signed by one or more authorities, +// those signatures will be checked, and any verification errors will be +// returned. +func ParseKRL(in []byte) (*KRL, error) { + orig := in + + var header krlHeader + if err := ssh.Unmarshal(in, &header); err != nil { + return nil, fmt.Errorf("krl: while parsing header: %v", err) + } + if header.KRLMagic != krlMagic { + return nil, fmt.Errorf("krl: bad magic value %x", header.KRLMagic) + } + if header.KRLFormatVersion != 1 { + return nil, fmt.Errorf("krl: bad format version %v", header.KRLFormatVersion) + } + krl := &KRL{ + Version: header.KRLVersion, + GeneratedDate: header.GeneratedDate, + Comment: header.Comment, + } + in = header.Rest + + for len(in) > 0 && in[0] != 4 { // // KRL_SECTION_SIGNATURE + var sdata krlSection + if err := ssh.Unmarshal(in, &sdata); err != nil { + return nil, fmt.Errorf("krl: malformed section: %v", err) + } + in = sdata.Rest + + var err error + var section KRLSection + switch sdata.SectionType { + case 1: // KRL_SECTION_CERTIFICATES + section, err = parseCertificateSection(sdata.SectionData) + case 2: // KRL_SECTION_EXPLICIT_KEY + section, err = parseExplicitKeySection(sdata.SectionData) + case 3: // KRL_SECTION_FINGERPRINT_SHA1 + section, err = parseFingerprintSection(sdata.SectionData) + default: + return nil, fmt.Errorf("krl: unexpected section type %d", sdata.SectionType) + } + if err != nil { + return nil, err + } + krl.Sections = append(krl.Sections, section) + } + + var signingErrors KRLSigningErrors + for len(in) > 0 { + var sigHeader krlSignatureHeader + if err := ssh.Unmarshal(in, &sigHeader); err != nil { + return nil, fmt.Errorf("krl: malfored signature header: %v", err) + } + in = sigHeader.Rest + + key, err := ssh.ParsePublicKey(sigHeader.SignatureKey) + if err != nil { + return nil, fmt.Errorf("krl: malformed signing key: %v", err) + } + + var sig krlSignature + if err := ssh.Unmarshal(in, &sig); err != nil { + return nil, fmt.Errorf("krl: malfored signature wrapper: %v", err) + } + in = sig.Rest + + sshsig := new(ssh.Signature) + if err := ssh.Unmarshal(sig.Signature, sshsig); err != nil { + return nil, fmt.Errorf("krl: malformed signature: %v", err) + } + + // The entire KRL up until immediately after the signature + // header is signed. + data := orig[:len(orig)-len(sigHeader.Rest)] + + krl.SigningKeys = append(krl.SigningKeys, key) + signingErrors = append(signingErrors, key.Verify(data, sshsig)) + } + + return krl, signingErrors.err() +} + +func parseCertificateSection(in []byte) (*KRLCertificateSection, error) { + var header krlCertificateSectionHeader + if err := ssh.Unmarshal(in, &header); err != nil { + return nil, fmt.Errorf("krl: while parsing certificate section header: %v", err) + } + ca, err := ssh.ParsePublicKey(header.CAKey) + if err != nil { + return nil, fmt.Errorf("krl: while parsing CA key: %v", err) + } + k := &KRLCertificateSection{CA: ca} + in = header.Rest + for len(in) > 0 { + var section krlCertificateSection + if err := ssh.Unmarshal(in, §ion); err != nil { + return nil, fmt.Errorf("krl: malformed certificate section: %v", err) + } + in = section.Rest + var err error + var subsection KRLCertificateSubsection + switch section.CertSectionType { + case krlSectionCertSerialList: + subsection, err = parseCertSerialList(section.CertSectionData) + case krlSectionCertSerialRange: + subsection, err = parseCertSerialRange(section.CertSectionData) + case krlSectionCertSerialBitmap: + subsection, err = parseCertSerialBitmap(section.CertSectionData) + case krlSectionCertKeyId: + subsection, err = parseCertKeyID(section.CertSectionData) + default: + return nil, fmt.Errorf("krl: unexpected cert section type %x", in[0]) + } + if err != nil { + return nil, err + } + k.Sections = append(k.Sections, subsection) + } + + return k, nil +} + +func parseCertSerialList(in []byte) (*KRLCertificateSerialList, error) { + s := &KRLCertificateSerialList{} + for len(in) > 0 { + var list krlSerialList + if err := ssh.Unmarshal(in, &list); err != nil { + return nil, fmt.Errorf("krl: while parsing serial in list: %v", err) + } + in = list.Rest + *s = append(*s, list.RevokedCertSerial) + } + return s, nil +} + +func parseCertSerialRange(in []byte) (*KRLCertificateSerialRange, error) { + var s krlSerialRange + if err := ssh.Unmarshal(in, &s); err != nil { + return nil, fmt.Errorf("krl: while parsing serial range: %v", err) + } + return &KRLCertificateSerialRange{ + Min: s.SerialMin, + Max: s.SerialMax, + }, nil +} + +func parseCertSerialBitmap(in []byte) (*KRLCertificateSerialBitmap, error) { + var s krlSerialBitmap + if err := ssh.Unmarshal(in, &s); err != nil { + return nil, fmt.Errorf("krl: while parsing serial bitmap: %v", err) + } + if bl := s.RevokedKeysBitmap.BitLen(); bl > krlMaxBitmapSize { + return nil, fmt.Errorf("krl: serial bitmap too wide: %v", bl) + } + return &KRLCertificateSerialBitmap{ + Offset: s.SerialOffset, + Bitmap: s.RevokedKeysBitmap, + }, nil +} + +func parseCertKeyID(in []byte) (*KRLCertificateKeyID, error) { + s := &KRLCertificateKeyID{} + for len(in) > 0 { + var list krlKeyID + if err := ssh.Unmarshal(in, &list); err != nil { + return nil, fmt.Errorf("krl: while parsing key id in list: %v", err) + } + in = list.Rest + *s = append(*s, list.KeyID) + } + return s, nil +} + +func parseExplicitKeySection(in []byte) (*KRLExplicitKeySection, error) { + s := &KRLExplicitKeySection{} + for len(in) > 0 { + var list krlExplicitKey + if err := ssh.Unmarshal(in, &list); err != nil { + return nil, fmt.Errorf("krl: while parsing explicit key in list: %v", err) + } + in = list.Rest + key, err := ssh.ParsePublicKey(list.PublicKeyBlob) + if err != nil { + return nil, fmt.Errorf("krl: while parsing explicit key: %v", err) + } + *s = append(*s, key) + } + return s, nil +} + +func parseFingerprintSection(in []byte) (*KRLFingerprintSection, error) { + s := &KRLFingerprintSection{} + for len(in) > 0 { + var list krlFingerprintSHA1 + if err := ssh.Unmarshal(in, &list); err != nil { + return nil, fmt.Errorf("krl: while parsing fingerprint in list: %v", err) + } + in = list.Rest + if len(list.PublicKeyHash) != sha1.Size { + return nil, fmt.Errorf("krl: key fingerprint wrong length for SHA1: %x", list.PublicKeyHash) + } + var sha [sha1.Size]byte + copy(sha[:], list.PublicKeyHash) + *s = append(*s, sha) + } + return s, nil +} |