Add ROCA weak key checking (#3189)
Thanks to @titanous for the library!
This commit is contained in:
parent
2f263f8ed5
commit
5df083a57e
|
@ -232,6 +232,10 @@
|
|||
"Comment": "v1.1.3-8-g0744955",
|
||||
"Rev": "0744955171b0b6e1871ff9d7366abc2b7a7fcec0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/titanous/rocacheck",
|
||||
"Rev": "afe73141d399b0c79c3d6412d4bdcf4c672c496a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/weppos/publicsuffix-go/publicsuffix",
|
||||
"Comment": "v0.3.2-24-g02da67f",
|
||||
|
|
|
@ -4,9 +4,9 @@ package features
|
|||
|
||||
import "fmt"
|
||||
|
||||
const _FeatureFlag_name = "unusedAllowAccountDeactivationAllowKeyRolloverResubmitMissingSCTsOnlyUseAIAIssuerURLAllowTLS02ChallengesGenerateOCSPEarlyReusePendingAuthzCountCertificatesExactRandomDirectoryEntryIPv6FirstDirectoryMetaAllowRenewalFirstRLRecheckCAALegacyCAAUDPDNS"
|
||||
const _FeatureFlag_name = "unusedAllowAccountDeactivationAllowKeyRolloverResubmitMissingSCTsOnlyUseAIAIssuerURLAllowTLS02ChallengesGenerateOCSPEarlyReusePendingAuthzCountCertificatesExactRandomDirectoryEntryIPv6FirstDirectoryMetaAllowRenewalFirstRLRecheckCAALegacyCAAUDPDNSROCACheck"
|
||||
|
||||
var _FeatureFlag_index = [...]uint8{0, 6, 30, 46, 69, 84, 104, 121, 138, 160, 180, 189, 202, 221, 231, 240, 246}
|
||||
var _FeatureFlag_index = [...]uint8{0, 6, 30, 46, 69, 84, 104, 121, 138, 160, 180, 189, 202, 221, 231, 240, 246, 255}
|
||||
|
||||
func (i FeatureFlag) String() string {
|
||||
if i < 0 || i >= FeatureFlag(len(_FeatureFlag_index)-1) {
|
||||
|
|
|
@ -29,6 +29,7 @@ const (
|
|||
RecheckCAA
|
||||
LegacyCAA
|
||||
UDPDNS
|
||||
ROCACheck
|
||||
)
|
||||
|
||||
// List of features and their default value, protected by fMu
|
||||
|
@ -49,6 +50,7 @@ var features = map[FeatureFlag]bool{
|
|||
RecheckCAA: false,
|
||||
LegacyCAA: false,
|
||||
UDPDNS: false,
|
||||
ROCACheck: false,
|
||||
}
|
||||
|
||||
var fMu = new(sync.RWMutex)
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
"sync"
|
||||
|
||||
berrors "github.com/letsencrypt/boulder/errors"
|
||||
"github.com/letsencrypt/boulder/features"
|
||||
"github.com/titanous/rocacheck"
|
||||
)
|
||||
|
||||
// To generate, run: primes 2 752 | tr '\n' ,
|
||||
|
@ -233,6 +235,11 @@ func (policy *KeyPolicy) goodKeyRSA(key rsa.PublicKey) (err error) {
|
|||
if checkSmallPrimes(modulus) {
|
||||
return berrors.MalformedError("key divisible by small prime")
|
||||
}
|
||||
// Check for weak keys generated by Infineon hardware
|
||||
// (see https://crocs.fi.muni.cz/public/papers/rsa_ccs17)
|
||||
if features.Enabled(features.ROCACheck) && rocacheck.IsWeak(&key) {
|
||||
return berrors.MalformedError("key generated by vulnerable Infineon-based hardware")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ import (
|
|||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"log"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/letsencrypt/boulder/features"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
|
@ -84,6 +86,22 @@ func TestModulusDivisibleBy752(t *testing.T) {
|
|||
test.AssertError(t, testingPolicy.GoodKey(&key), "Should have rejected modulus divisible by 751.")
|
||||
}
|
||||
|
||||
func TestROCA(t *testing.T) {
|
||||
err := features.Set(map[string]bool{"ROCACheck": true})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
n, ok := big.NewInt(1).SetString("19089470491547632015867380494603366846979936677899040455785311493700173635637619562546319438505971838982429681121352968394792665704951454132311441831732124044135181992768774222852895664400681270897445415599851900461316070972022018317962889565731866601557238345786316235456299813772607869009873279585912430769332375239444892105064608255089298943707214066350230292124208314161171265468111771687514518823144499250339825049199688099820304852696380797616737008621384107235756455735861506433065173933123259184114000282435500939123478591192413006994709825840573671701120771013072419520134975733578923370992644987545261926257", 10)
|
||||
if !ok {
|
||||
t.Fatal("failed to parse")
|
||||
}
|
||||
key := rsa.PublicKey{
|
||||
N: n,
|
||||
E: 65537,
|
||||
}
|
||||
test.AssertError(t, testingPolicy.GoodKey(&key), "Should have rejected ROCA-weak key.")
|
||||
}
|
||||
|
||||
func TestGoodKey(t *testing.T) {
|
||||
private, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
test.AssertNotError(t, err, "Error generating key")
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
]
|
||||
},
|
||||
"features": {
|
||||
"ROCACheck": true,
|
||||
"UDPDNS": true,
|
||||
"AllowKeyRollover": true,
|
||||
"AllowTLS02Challenges": true,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"timeout": "15s"
|
||||
},
|
||||
"features": {
|
||||
"ROCACheck": true,
|
||||
"AllowAccountDeactivation": true,
|
||||
"AllowKeyRollover": true,
|
||||
"UseAIAIssuerURL": true,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017, Jonathan Rudenberg
|
||||
Copyright (c) 2017, CRoCS, EnigmaBridge Ltd.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
|||
# rocacheck [](https://godoc.org/github.com/titanous/rocacheck)
|
||||
|
||||
Package rocacheck is a Go implementation of the [key fingerprint
|
||||
algorithm](https://github.com/crocs-muni/roca) that checks if an RSA key was
|
||||
generated by broken Infineon code and is vulnerable to factorization via the
|
||||
[Return of Coppersmith's Attack
|
||||
(ROCA)](https://crocs.fi.muni.cz/public/papers/rsa_ccs17) / CVE-2017-15361.
|
|
@ -0,0 +1,52 @@
|
|||
// Package rocacheck checks if a key was generated by broken Infineon code and
|
||||
// is vulnerable to factorization via the Return of Coppersmith's Attack (ROCA)
|
||||
// / CVE-2017-15361.
|
||||
package rocacheck
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
Prime *big.Int
|
||||
Fingerprints map[int64]struct{}
|
||||
}
|
||||
|
||||
var tests = make([]test, 17)
|
||||
|
||||
func init() {
|
||||
bigOne := big.NewInt(1)
|
||||
n := &big.Int{}
|
||||
// relations table from https://github.com/crocs-muni/roca/pull/40
|
||||
for i, r := range [][2]int64{
|
||||
{2, 11}, {6, 13}, {8, 17}, {9, 19}, {3, 37}, {26, 53}, {20, 61},
|
||||
{35, 71}, {24, 73}, {13, 79}, {6, 97}, {51, 103}, {53, 107},
|
||||
{54, 109}, {42, 127}, {50, 151}, {78, 157},
|
||||
} {
|
||||
fps := make(map[int64]struct{})
|
||||
bp := big.NewInt(r[1])
|
||||
br := big.NewInt(r[0])
|
||||
for j := int64(0); j < r[1]; j++ {
|
||||
if n.Exp(big.NewInt(j), br, bp).Cmp(bigOne) == 0 {
|
||||
fps[j] = struct{}{}
|
||||
}
|
||||
}
|
||||
tests[i] = test{
|
||||
Prime: big.NewInt(r[1]),
|
||||
Fingerprints: fps,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsWeak returns true if a RSA public key is vulnerable to Return of
|
||||
// Coppersmith's Attack (ROCA).
|
||||
func IsWeak(k *rsa.PublicKey) bool {
|
||||
tmp := &big.Int{}
|
||||
for _, t := range tests {
|
||||
if _, ok := t.Fingerprints[tmp.Mod(k.N, t.Prime).Int64()]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Loading…
Reference in New Issue