Skip to content

Commit

Permalink
add more extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
pete911 committed Dec 16, 2024
1 parent a1c8af6 commit c2cda7b
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 46 deletions.
100 changes: 88 additions & 12 deletions pkg/cert/asn.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,49 @@ func ToKeyUsage(in []byte) ([]string, error) {
return toKeyUsage(out), nil
}

// AuthorityInfoAccessSyntax ::=
// SEQUENCE SIZE (1..MAX) OF AccessDescription
//
// AccessDescription ::= SEQUENCE {
// accessMethod OBJECT IDENTIFIER,
// accessLocation GeneralName }

type AccessDescription struct {
AccessMethod string
AccessLocation string
}

func ToAuthorityInformationAccess(in []byte) ([]AccessDescription, error) {
sequence := asn1.RawValue{Tag: asn1.TagSequence}
if _, err := asn1.Unmarshal(in, &sequence); err != nil {
return nil, err
}
in = sequence.Bytes

var accesses []AccessDescription
for {
var out struct {
AccessMethod asn1.ObjectIdentifier
AccessLocation asn1.RawValue // TODO parse to general name
}
rest, err := asn1.Unmarshal(in, &out)
if err != nil {
return nil, err
}
name := toGeneralName(out.AccessLocation)
oid := out.AccessMethod.String()
accesses = append(accesses, AccessDescription{
AccessMethod: fmt.Sprintf("%s (%s)", accessDescriptorsOIDs[oid], oid),
AccessLocation: fmt.Sprintf("%s: %s", name.Type, name.Value),
})
if len(rest) == 0 {
break
}
in = rest
}
return accesses, nil
}

func ToExtendedKeyUsage(in []byte) ([]string, error) {
sequence := asn1.RawValue{Tag: asn1.TagSequence}
if _, err := asn1.Unmarshal(in, &sequence); err != nil {
Expand All @@ -252,7 +295,7 @@ func ToExtendedKeyUsage(in []byte) ([]string, error) {

extKeyUsage := out.String()
if v, ok := idKpOIDs[extKeyUsage]; ok {
extKeyUsage = fmt.Sprintf("%s - %s", extKeyUsage, v)
extKeyUsage = fmt.Sprintf("%s (%s)", v, extKeyUsage)
}
extKeyUsages = append(extKeyUsages, extKeyUsage)

Expand Down Expand Up @@ -312,7 +355,7 @@ func ToCertificatePolicies(in []byte) ([]string, error) {
policy := out.PolicyIdentifier.String()
if v, ok := certificatePoliciesOIDs[policy]; ok {
// if we find correct oid, use that
policy = fmt.Sprintf("%s - %s", policy, v)
policy = fmt.Sprintf("%s (%s)", v, policy)
}
// TODO - policy qualifiers when I find appropriate cert to test

Expand All @@ -326,6 +369,14 @@ func ToCertificatePolicies(in []byte) ([]string, error) {
return policies, nil
}

func ToSignedCertificateTimestampList(in []byte) ([]byte, error) {
var out asn1.RawValue // OCTET STRING
if _, err := asn1.Unmarshal(in, &out); err != nil {
return nil, err
}
return out.Bytes, nil
}

// --- bit strings and conversions ---

// order is important, it matches either asn tag or bit string
Expand Down Expand Up @@ -420,26 +471,34 @@ func toGeneralName(in asn1.RawValue) GeneralName {
// --- OIDs ---

var certificatePoliciesOIDs = map[string]string{
"2.23.140.1.1": "ev-guidelines",
"2.5.29.32.0": "any policy",
"2.5.29.32.2": "ldap",

"2.23.140.1.1": "ev guidelines",

// baseline requirements
"2.23.140.1.2.1": "domain-validated",
"2.23.140.1.2.2": "organization-validated",
"2.23.140.1.2.3": "individual-validated",
"2.23.140.1.2.1": "domain validated",
"2.23.140.1.2.2": "organization validated",
"2.23.140.1.2.3": "individual validated",

"2.23.140.1.3": "extended-validation-codesigning",
"2.23.140.1.3": "extended-validation codesigning",

// code-signing-requirements
"2.23.140.1.4.1": "code-signing",
"2.23.140.1.4.1": "code signing",
"2.23.140.1.4.2": "timestamping",

// smime
"2.23.140.1.5.1": "mailbox-validated",
"2.23.140.1.5.2": "organization-validated",
"2.23.140.1.5.3": "sponsor-validated",
"2.23.140.1.5.4": "individual-validated",
"2.23.140.1.5.1": "mailbox validated",
"2.23.140.1.5.2": "organization validated",
"2.23.140.1.5.3": "sponsor validated",
"2.23.140.1.5.4": "individual validated",

"2.23.140.31": "onion-ev",

// google trust services, certificate policy
"1.3.6.1.4.1.11129.2.5.3.1": "signed http exchanges",
"1.3.6.1.4.1.11129.2.5.3.2": "client authentication",
"1.3.6.1.4.1.11129.2.5.3.3": "document signing",
}

var idKpOIDs = map[string]string{
Expand All @@ -454,3 +513,20 @@ var idKpOIDs = map[string]string{
"1.3.6.1.5.5.7.3.9": "OCSP signing",
// TODO add the rest
}

var accessDescriptorsOIDs = map[string]string{
"1.3.6.1.5.5.7.48.1": "ocsp",
"1.3.6.1.5.5.7.48.2": "ca issuers",
"1.3.6.1.5.5.7.48.3": "time stamping",
"1.3.6.1.5.5.7.48.4": "dvcs",
"1.3.6.1.5.5.7.48.5": "ca repository",
"1.3.6.1.5.5.7.48.6": "http certs",
"1.3.6.1.5.5.7.48.7": "http crls",
"1.3.6.1.5.5.7.48.8": "xkms",
"1.3.6.1.5.5.7.48.9": "signed object repository",
"1.3.6.1.5.5.7.48.10": "rpki manifest",
"1.3.6.1.5.5.7.48.11": "signed object",
"1.3.6.1.5.5.7.48.12": "cmc",
"1.3.6.1.5.5.7.48.13": "rpki notify",
"1.3.6.1.5.5.7.48.14": "stir tn list",
}
5 changes: 4 additions & 1 deletion pkg/cert/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ func (c Certificate) Extensions() string {
if v.Critical {
name = fmt.Sprintf("%s [critical]", name)
}
lines = append(lines, fmt.Sprintf("%s\n %s", name, v.Value))
lines = append(lines, name)
for _, line := range v.Values {
lines = append(lines, fmt.Sprintf(" %s", line))
}
}
return strings.Join(lines, "\n")
}
Expand Down
95 changes: 62 additions & 33 deletions pkg/cert/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Extension struct {
Name string
Oid string
Critical bool
Value string
Values []string
}

func ToExtensions(in []pkix.Extension) []Extension {
Expand All @@ -22,20 +22,20 @@ func ToExtensions(in []pkix.Extension) []Extension {
Name: name,
Oid: v.Id.String(),
Critical: v.Critical,
Value: value,
Values: value,
})
}
return out
}

func parseExtension(in pkix.Extension) (string, string) {
func parseExtension(in pkix.Extension) (string, []string) {
if fn, ok := extensionsByOid[in.Id.String()]; ok {
return fn(in.Value)
}
return "-", in.Id.String()
return "-N/A-", []string{in.Id.String()}
}

var extensionsByOid = map[string]func(in []byte) (string, string){
var extensionsByOid = map[string]func(in []byte) (string, []string){
"2.5.29.35": parseAuthorityKeyIdentifier,
"2.5.29.14": parseSubjectKeyIdentifier,
"2.5.29.15": parseKeyUsage,
Expand All @@ -52,11 +52,9 @@ var extensionsByOid = map[string]func(in []byte) (string, string){
//"2.5.29.54": parseInhibitAnyPolicy,
//"2.5.29.46": parseFreshestCRL,
// private internet extensions
//"1.3.6.1.5.5.7.1": parseAuthorityInformationAccess,
"1.3.6.1.5.5.7.1.1": parseAuthorityInformationAccess,
//"1.3.6.1.5.5.7.11": parseSubjectInformationAccess,
// TODO
//"1.3.6.1.5.5.7.1.1": parseAuthorityInfoAccessSyntax
// "1.3.6.1.4.1.11129.2.4.2" parseOID ???
"1.3.6.1.4.1.11129.2.4.2": parseSignedCertificateTimestampList,
}

// AuthorityKeyIdentifier ::= SEQUENCE {
Expand All @@ -65,11 +63,11 @@ var extensionsByOid = map[string]func(in []byte) (string, string){
// authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
// -- authorityCertIssuer and authorityCertSerialNumber MUST both
// -- be present or both be absent
func parseAuthorityKeyIdentifier(in []byte) (string, string) {
func parseAuthorityKeyIdentifier(in []byte) (string, []string) {
name := "Authority Key Identifier"
out, err := ToAuthorityKeyIdentifier(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}

fields := []string{formatHexArray(out.KeyIdentifier)}
Expand All @@ -80,17 +78,17 @@ func parseAuthorityKeyIdentifier(in []byte) (string, string) {
if out.AuthorityCertSerialNumber != 0 {
fields = append(fields, fmt.Sprintf("Authority Cert SN: %d", out.AuthorityCertSerialNumber))
}
return name, strings.Join(fields, ", ")
return name, fields
}

// SubjectKeyIdentifier ::= KeyIdentifier
func parseSubjectKeyIdentifier(in []byte) (string, string) {
func parseSubjectKeyIdentifier(in []byte) (string, []string) {
name := "Subject Key Identifier"
out := asn1.RawValue{Tag: asn1.TagOctetString}
if _, err := asn1.Unmarshal(in, &out); err != nil {
return name, err.Error()
return name, []string{err.Error()}
}
return name, formatHexArray(out.Bytes)
return name, []string{formatHexArray(out.Bytes)}
}

// KeyUsage ::= BIT STRING {
Expand All @@ -104,40 +102,40 @@ func parseSubjectKeyIdentifier(in []byte) (string, string) {
// cRLSign (6),
// encipherOnly (7),
// decipherOnly (8) }
func parseKeyUsage(in []byte) (string, string) {
func parseKeyUsage(in []byte) (string, []string) {
name := "Key Usage"
out, err := ToKeyUsage(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}
return name, strings.Join(out, ", ")
return name, out
}

func parseCertificatePolicies(in []byte) (string, string) {
func parseCertificatePolicies(in []byte) (string, []string) {
name := "Certificate Policies"
out, err := ToCertificatePolicies(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}
return name, strings.Join(out, ", ")
return name, out
}

func parseSubjectAltName(in []byte) (string, string) {
func parseSubjectAltName(in []byte) (string, []string) {
name := "Subject Alt. Name"
out, err := ToGeneralNames(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}
return name, strings.Join(out, ", ")
return name, out
}

func parseExtendedKeyUsage(in []byte) (string, string) {
func parseExtendedKeyUsage(in []byte) (string, []string) {
name := "Extended Key Usage"
out, err := ToExtendedKeyUsage(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}
return name, strings.Join(out, ", ")
return name, out
}

// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
Expand All @@ -150,11 +148,11 @@ func parseExtendedKeyUsage(in []byte) (string, string) {
// DistributionPointName ::= CHOICE {
// fullName [0] GeneralNames,
// nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
func parseCRLDistributionPoints(in []byte) (string, string) {
func parseCRLDistributionPoints(in []byte) (string, []string) {
name := "CRL Distribution Points"
out, err := ToCRLDistributionPoints(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}
var points []string
for _, v := range out {
Expand All @@ -172,22 +170,53 @@ func parseCRLDistributionPoints(in []byte) (string, string) {
points = append(points, strings.Join(point, " "))
}
}
return name, strings.Join(points, "; ")
return name, points
}

// AuthorityInfoAccessSyntax ::=
// SEQUENCE SIZE (1..MAX) OF AccessDescription
//
// AccessDescription ::= SEQUENCE {
// accessMethod OBJECT IDENTIFIER,
// accessLocation GeneralName }

func parseAuthorityInformationAccess(in []byte) (string, []string) {
name := "Authority Information Access"
out, err := ToAuthorityInformationAccess(in)
if err != nil {
return name, []string{err.Error()}
}
var fields []string
for _, v := range out {
fields = append(fields, fmt.Sprintf("%s - %s", v.AccessMethod, v.AccessLocation))
}
return name, fields
}

func parseSignedCertificateTimestampList(in []byte) (string, []string) {
name := "CT Precertificate SCTs"
return name, []string{"..."}
// TODO parse "Certificate Transparency", validate against openssl x509 output
//out, err := ToSignedCertificateTimestampList(in)
//if err != nil {
// return name, []string{err.Error()}
//}
//return name, []string{formatHexArray(out)}
}

// BasicConstraints ::= SEQUENCE {
// cA BOOLEAN DEFAULT FALSE,
// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
func parseBasicConstraints(in []byte) (string, string) {
func parseBasicConstraints(in []byte) (string, []string) {
name := "Basic Constraints"
out, err := ToBasicConstraints(in)
if err != nil {
return name, err.Error()
return name, []string{err.Error()}
}

fields := []string{fmt.Sprintf("CA: %t", out.CA)}
if out.PathLenConstraint != 0 {
fields = append(fields, fmt.Sprintf("PathLenConstraint: %d", out.PathLenConstraint))
}
return name, strings.Join(fields, ", ")
return name, fields
}

0 comments on commit c2cda7b

Please sign in to comment.