-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add lint which checks for explicitly encoded critical default values #639
Comments
I'm sorry, @alex, but I do not believe that this is quite feasible in our codebase without some interesting gymnastics. The reason is as follows... Consider the definition of a // Extension represents the ASN.1 structure of the same name. See RFC
// 5280, section 4.2.
type Extension struct {
Id asn1.ObjectIdentifier
Critical bool `asn1:"optional"`
Value []byte
} The Take the following Go playground sample... package main
import (
"fmt"
"crypto/x509/pkix"
)
func main() {
fmt.Println(pkix.Extension{})
} We could, conceivable, modify type Extension struct {
Id asn1.ObjectIdentifier
Critical *bool `asn1:"optional"`
Value []byte
} That is, a pointer to a Alternatively, we could extend the struct to include this information at the time of deserialization. type Extension struct {
Id asn1.ObjectIdentifier
Critical bool `asn1:"optional"`
CriticalWasEncoded bool
Value []byte
} @cpu or @zakird could you think of simpler ways to pull off a lint such as this? |
My suggestion would be to do the |
Would that not involve yet another fork of func (l *Lint) Execute(c *x509.Certificate) *lint.LintResult {
c2 := privateX509.ParseCertificate(c.Raw)
for _, ext := range c2.Extensions {
if !*ext {
panic("boo")
}
}
} That is certainly non-evasive. However, it is taking a thermonuclear device to a worm. |
I don't think it'd require a full fork, it's really just type certificate struct {
TBSCertificate tbsCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
Extensions []MyExtension `asn1:"optional,explicit,tag:3"`
}
type validity struct {
NotBefore, NotAfter time.Time
}
type publicKeyInfo struct {
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
} And then an |
That's actually a good point. I'm not getting any luck with the following definition, however, so I'm gonna debug what I'm doing wrong here (I even left the type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Raw asn1.RawContent
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
Extensions []Extension `asn1:"optional,explicit,tag:3"`
}
type validity struct {
NotBefore, NotAfter time.Time
}
type publicKeyInfo struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
type Extension struct {
Id asn1.ObjectIdentifier
Critical bool `asn1:"optional"`
Value []byte
} |
(figured it out, |
Alas, boo. I don't think the // Given a reflected Go type, getUniversalType returns the default tag number
// and expected compound flag.
func getUniversalType(t reflect.Type) (matchAny bool, tagNumber int, isCompound, ok bool) {
switch t {
case rawValueType:
return true, -1, false, true
case objectIdentifierType:
return false, TagOID, false, true
case bitStringType:
return false, TagBitString, false, true
case timeType:
return false, TagUTCTime, false, true
case enumeratedType:
return false, TagEnum, false, true
case bigIntType:
return false, TagInteger, false, true
}
switch t.Kind() {
case reflect.Bool:
return false, TagBoolean, false, true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return false, TagInteger, false, true
case reflect.Struct:
return false, TagSequence, true, true
case reflect.Slice:
if t.Elem().Kind() == reflect.Uint8 {
return false, TagOctetString, false, true
}
if strings.HasSuffix(t.Name(), "SET") {
return false, TagSet, true, true
}
return false, TagSequence, true, true
case reflect.String:
return false, TagPrintableString, false, true
}
return false, 0, false, false
} This naturally results in a |
This is now addressed by #839 :) |
From ITU X.690:
From RFC 5280:
therefore
critical
should never be encoded with a false value.Some issuing software does do this though, so a lint to capture it would be valuable.
(My proximate motivation: pyca/cryptography#6368)
The text was updated successfully, but these errors were encountered: