A vulnerability is a weakness in a system or implementation that an attacker can exploit to violate security properties. Cryptographic implementations are especially exposed because engineering mistakes are easier to exploit than the underlying mathematical ideas. section 1.0
Typical vulnerability patterns include:
- Treating a cryptographic primitive as safe while using it in a flawed protocol, as WEP did with RC4, allowing attackers to recover Wi-Fi keys from captured traffic. section 4.3
- Skipping required validation, as with PKCS #1 v1.5 padding, where accepting any bytes between the header and separator enables selective signature forgery. section 9.6.2
- Implementing cryptography without thorough testing, making exploitable behavior easier to introduce and harder to detect. section 1.4
Forged RSA signatures
An insecure verifier checks the 0x00 0x01 header, searches for a separator, and ignores the required FF padding bytes. With a public exponent of 3, an attacker can construct signatures that pass verification without possessing the private key, although the attack is selective. section 9.6.2
Listing 9.12 impl_rsa_bleichenbacher_sig.go
func VerifyPKCS1v15Insecure(pub *rsa.PublicKey, hashAlg crypto.Hash,
digest []byte, sig []byte) error {
fmt.Printf("hashAlg: %s\n", hashAlg)
fmt.Printf("digest: 0x%X\n", digest)
fmt.Printf("sig: 0x%X\n", sig)
eNum := new(big.Int).SetInt64(int64(pub.E))
sigNum := new(big.Int).SetBytes(sig)
sigExpE := new(big.Int).Exp(sigNum, eNum, pub.N) #1
sigExpEBytes := sigExpE.Bytes()
sigCleartext := make([]byte, ModulusBits/8)
offset := len(sigCleartext) - len(sigExpEBytes)
for i := offset; i < len(sigCleartext); i++ {
sigCleartext[i] = sigExpEBytes[i-offset]
}
fmt.Printf("sigCleartext: 0x%X\n", sigCleartext)
if bytes.Compare(sigCleartext[0:2], []byte{0x00, 0x01}) != 0 {
return fmt.Errorf("verification failed: header mismatch")
}
sepIdx := bytes.IndexByte(sigCleartext[2:], byte(0x00)) + 3 #2
var hashAsn1Identifier []byte
switch hashAlg {
case crypto.MD5:
hashAsn1Identifier = []byte(HashAsn1Md5)
case crypto.SHA1:
hashAsn1Identifier = []byte(HashAsn1Sha1)
case crypto.SHA256:
hashAsn1Identifier = []byte(HashAsn1Sha256)
}
if bytes.Compare(sigCleartext[sepIdx:sepIdx+len(hashAsn1Identifier)], hashAsn1Identifier) != 0 {
return fmt.Errorf("verification failed: asn1 identifier mismatch")
}
digestIdx := sepIdx + len(hashAsn1Identifier)
if bytes.Compare(sigCleartext[digestIdx:digestIdx+len(digest)], digest) != 0 {
return fmt.Errorf("verification failed: digest mismatch")
}
if len(sigCleartext) > digestIdx+len(digest) {
return fmt.Errorf("verification failed: trailing bytes")
}
return nil
}
Inspect the vulnerable Go verifier to trace modular exponentiation, cleartext reconstruction, header checking, separator search, and the omitted padding check. section 9.6.2















