package models import ( "strconv" "github.com/jinzhu/gorm" "github.com/jmoiron/jsonq" "github.com/sirupsen/logrus" ) // LeafCertExtensions extends the LeafCert object. type LeafCertExtensions struct { gorm.Model KeyUsage string `json:"keyUsage"` ExtendedKeyUsage string `json:"extendedKeyUsage"` BasicConstrains string `json:"basicConstrains"` SubjectKeyIdentifier string `json:"subjectKeyIdentifier"` AuthorityInfoAccess string `json:"authorityInfoAccess"` SubjectAltName string `json:"subjectAltName"` CertificatePolicies string `json:"certificatePolicies"` } // LeafCertSubject is the subject of the LeafCert object. type LeafCertSubject struct { gorm.Model Aggregated string `json:"aggregated"` C string `json:"C"` ST string `json:"ST"` L string `json:"L"` O string `json:"O"` OU string `json:"OU"` CN string `json:"CN"` } // LeafCertStruct represents the LeafCert object. type LeafCertStruct struct { gorm.Model Subject LeafCertSubject `json:"subject"` Extensions LeafCertExtensions `json:"extensions"` NotBefore int `json:"not_before"` NotAfter int `json:"not_after"` SerialNumber string `json:"serial_number"` Fingerprint string `json:"fingerprint"` AsDer string `json:"as_der"` // AllDomains []string `json:"all_domains"` } // Source is the object ofr the URL and its name. type Source struct { gorm.Model URL string `json:"url"` Name string `json:"name"` } // CertStreamData is the data contained in a CertStream payload. type CertStreamData struct { gorm.Model UpdateType string `json:"update_type"` LeafCert LeafCertStruct `json:"leaf_cert"` Chain []LeafCertStruct `json:"chain"` CertIndex int `json:"cert_index"` Seen int `json:"seen"` Source Source `json:"source"` CertStreamStruct uint } // CertStreamStruct reprensts a payload received from CertStream. It has a type // and the content is stored in Data. type CertStreamStruct struct { gorm.Model MessageType string Data CertStreamData `json:"data"` } // Certificate is the main model saved and exposed to the API. type Certificate struct { gorm.Model Aggregated string `json:"aggregated"` C string `json:"C"` ST string `json:"ST"` L string `json:"L"` O string `json:"O"` OU string `json:"OU"` CN string `json:"CN"` Fingerprint string `json:"fingerprint"` } // ExtractCertFromStream builds the structures before saving them. It uses the // power of jsonq to parse quickly the json stream. // The base structure is coming from : https://github.com/CaliDog/certstream-go#example-data-structure func ExtractCertFromStream(input jsonq.JsonQuery) (*Certificate, error) { // LeafCertStruct leafCertStruct, err := extractLeafCertStruct(input) if err != nil { logrus.Error(err) } // CertStreamData > Source url, err := input.String("data", "source", "url") name, err := input.String("data", "source", "name") if err != nil { logrus.Error(err) } source := Source{ URL: url, Name: name, } // CertStreamData updateType, err := input.String("data", "update_type") certIndex, err := input.Int("data", "cert_index") seen, err := input.Int("data", "seen") chain, err := input.ArrayOfObjects("data", "chain") chainSlice := []LeafCertStruct{} for i := 0; i < len(chain); i++ { c, err := extractLeafCertChainStruct(input, strconv.Itoa(i)) if err != nil { logrus.Error("error extractLeafCertChainStruct: ", err) } chainSlice = append(chainSlice, c) } csd := CertStreamData{ UpdateType: updateType, LeafCert: leafCertStruct, Chain: chainSlice, CertIndex: certIndex, Seen: seen, Source: source, } // CertStreamStruct messageType, err := input.String("message_type") if err != nil { logrus.Error(err) } certStruct := CertStreamStruct{ MessageType: messageType, Data: csd, } res := Certificate{ Aggregated: certStruct.Data.LeafCert.Subject.Aggregated, C: certStruct.Data.LeafCert.Subject.C, ST: certStruct.Data.LeafCert.Subject.ST, L: certStruct.Data.LeafCert.Subject.L, O: certStruct.Data.LeafCert.Subject.O, OU: certStruct.Data.LeafCert.Subject.OU, CN: certStruct.Data.LeafCert.Subject.CN, Fingerprint: certStruct.Data.LeafCert.Fingerprint, } return &res, nil } func extractLeafCertChainStruct(input jsonq.JsonQuery, index string) (LeafCertStruct, error) { // LeafCertStruct > Subject aggregated, _ := input.String("data", "chain", index, "subject", "aggregated") c, _ := input.String("data", "chain", index, "subject", "C") st, _ := input.String("data", "chain", index, "subject", "ST") l, _ := input.String("data", "chain", index, "subject", "L") o, _ := input.String("data", "chain", index, "subject", "O") ou, _ := input.String("data", "chain", index, "subject", "OU") cn, _ := input.String("data", "chain", index, "subject", "CN") subject := LeafCertSubject{ Aggregated: aggregated, C: c, ST: st, L: l, O: o, OU: ou, CN: cn, } // LeafCertStruct > Extensions keyUsage, _ := input.String("data", "chain", index, "extensions", "keyUsage") extendedKeyUsage, _ := input.String("data", "chain", index, "extensions", "extendedKeyUsage") basicConstrains, _ := input.String("data", "chain", index, "extensions", "basicConstrains") subjectKeyIdentifier, _ := input.String("data", "chain", index, "extensions", "subjectKeyIdentifier") authorityInfoAccess, _ := input.String("data", "chain", index, "extensions", "authorityInfoAccess") subjectAltName, _ := input.String("data", "chain", index, "extensions", "subjectAltName") certificatePolicies, _ := input.String("data", "chain", index, "extensions", "certificatePolicies") extensions := LeafCertExtensions{ KeyUsage: keyUsage, ExtendedKeyUsage: extendedKeyUsage, BasicConstrains: basicConstrains, SubjectKeyIdentifier: subjectKeyIdentifier, AuthorityInfoAccess: authorityInfoAccess, SubjectAltName: subjectAltName, CertificatePolicies: certificatePolicies, } notBefore, _ := input.Int("data", "chain", "not_before") notAfter, _ := input.Int("data", "chain", "not_after") serialNumber, _ := input.String("data", "chain", "serialNumber") fingerprint, _ := input.String("data", "chain", "fingerprint") asDer, _ := input.String("data", "chain", "as_der") // allDomains, _ := input.ArrayOfStrings("data", "chain", "all_domains") return LeafCertStruct{ Subject: subject, Extensions: extensions, NotBefore: notBefore, NotAfter: notAfter, SerialNumber: serialNumber, Fingerprint: fingerprint, AsDer: asDer, // AllDomains: allDomains, }, nil } func extractLeafCertStruct(input jsonq.JsonQuery) (LeafCertStruct, error) { // LeafCertStruct > Subject aggregated, err := input.String("data", "leaf_cert", "subject", "aggregated") c, err := input.String("data", "leaf_cert", "subject", "C") st, err := input.String("data", "leaf_cert", "subject", "ST") l, err := input.String("data", "leaf_cert", "subject", "L") o, err := input.String("data", "leaf_cert", "subject", "O") ou, err := input.String("data", "leaf_cert", "subject", "OU") cn, err := input.String("data", "leaf_cert", "subject", "CN") if err != nil { logrus.Error(err) } subject := LeafCertSubject{ Aggregated: aggregated, C: c, ST: st, L: l, O: o, OU: ou, CN: cn, } // LeafCertStruct > Extensions keyUsage, _ := input.String("data", "leaf_cert", "extensions", "keyUsage") extendedKeyUsage, _ := input.String("data", "leaf_cert", "extensions", "extendedKeyUsage") basicConstrains, _ := input.String("data", "leaf_cert", "extensions", "basicConstrains") subjectKeyIdentifier, _ := input.String("data", "leaf_cert", "extensions", "subjectKeyIdentifier") authorityInfoAccess, _ := input.String("data", "leaf_cert", "extensions", "authorityInfoAccess") subjectAltName, _ := input.String("data", "leaf_cert", "extensions", "subjectAltName") certificatePolicies, _ := input.String("data", "leaf_cert", "extensions", "certificatePolicies") extensions := LeafCertExtensions{ KeyUsage: keyUsage, ExtendedKeyUsage: extendedKeyUsage, BasicConstrains: basicConstrains, SubjectKeyIdentifier: subjectKeyIdentifier, AuthorityInfoAccess: authorityInfoAccess, SubjectAltName: subjectAltName, CertificatePolicies: certificatePolicies, } notBefore, _ := input.Int("data", "leaf_cert", "not_before") notAfter, _ := input.Int("data", "leaf_cert", "not_after") serialNumber, _ := input.String("data", "leaf_cert", "serialNumber") fingerprint, _ := input.String("data", "leaf_cert", "fingerprint") asDer, _ := input.String("data", "leaf_cert", "as_der") // allDomains, _ := input.ArrayOfStrings("data", "leaf_cert", "all_domains") return LeafCertStruct{ Subject: subject, Extensions: extensions, NotBefore: notBefore, NotAfter: notAfter, SerialNumber: serialNumber, Fingerprint: fingerprint, AsDer: asDer, // AllDomains: allDomains, }, nil }