Skip to content

Commit

Permalink
simplicicaiton generation of ca, enhance test to ensure stable subject
Browse files Browse the repository at this point in the history
  • Loading branch information
cviecco committed Jun 9, 2024
1 parent 5fd5e96 commit cc403a7
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 38 deletions.
61 changes: 27 additions & 34 deletions lib/certgen/certgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
Expand Down Expand Up @@ -201,32 +200,6 @@ func GetSignerFromPEMBytes(privateKey []byte) (crypto.Signer, error) {
}
}

func getSignerHashFromPublic(pub interface{}) (crypto.Hash, error) {
// crypto.SHA256
switch pub := pub.(type) {
case *rsa.PublicKey:
return crypto.SHA256, nil
case *ecdsa.PublicKey:
switch pub.Curve {
case elliptic.P224(), elliptic.P256():
return crypto.SHA256, nil
case elliptic.P384():
return crypto.SHA384, nil
case elliptic.P521():
return crypto.SHA512, nil
default:
return 0, fmt.Errorf("x509: unknown elliptic curve")
}
//Ed25519 signatures (by default) dont have a prefered signer
case *ed25519.PublicKey, ed25519.PublicKey:
return 0, nil

default:
return 0, fmt.Errorf("unknown key type")
}

}

// ValidatePublicKeyStrenght checks if the "strength" of the key is good enough to be considered secure
// At this moment it checks for sizes of parameters only. For RSA it means bits>=2041 && exponent>=65537,
// For EC curves it means bitsize>=256. ec25519 is considered secure. All other public keys are not
Expand Down Expand Up @@ -266,6 +239,31 @@ func derBytesCertToCertAndPem(derBytes []byte) (*x509.Certificate, string, error
}
*/

// On the initial version of keymaster we used the base64 encoding
// of the sha256sum of the rsa signature of the sha256 of the
// common name. This to have a stable, key dependent
// serial number.
// Howeve this was a bad idea as:
// 1. Not all signers can use sha256
// 2. Not all signatures are stable.
//
// Thus we will keep the rsa behaviour for compatiblity reasons
// But for all other keys we will just return the pkix asn1 encoding
// of the public key
func getKMCompatbileKeyStableBytesForSerial(priv interface{}, commonName []byte) ([]byte, error) {
switch v := priv.(type) {
case *rsa.PrivateKey:
sum := sha256.Sum256(commonName)
return v.Sign(rand.Reader, sum[:], crypto.SHA256)
case *ecdsa.PrivateKey:
return x509.MarshalPKIXPublicKey(v.Public())
case ed25519.PrivateKey:
return x509.MarshalPKIXPublicKey(v.Public())
default:
return nil, fmt.Errorf("Type not recognized %T!\n", v)

Check warning on line 263 in lib/certgen/certgen.go

View check run for this annotation

Codecov / codecov/patch

lib/certgen/certgen.go#L262-L263

Added lines #L262 - L263 were not covered by tests
}
}

// return both an internal representation an the pem representation of the string
// As long as the issuer value matches THEN the serial number can be different every time
func GenSelfSignedCACert(commonName string, organization string, caPriv crypto.Signer) ([]byte, error) {
Expand All @@ -278,16 +276,11 @@ func GenSelfSignedCACert(commonName string, organization string, caPriv crypto.S
if err != nil {
return nil, err
}
sum := sha256.Sum256([]byte(commonName))
hashfunc, err := getSignerHashFromPublic(caPriv.Public())
if err != nil {
return nil, err
}
signedCN, err := caPriv.Sign(rand.Reader, sum[:], hashfunc)
keyStableBytes, err := getKMCompatbileKeyStableBytesForSerial(caPriv, []byte(commonName))
if err != nil {
return nil, err
}
sigSum := sha256.Sum256(signedCN)
sigSum := sha256.Sum256(keyStableBytes)
sig := base64.StdEncoding.EncodeToString(sigSum[:])
template := x509.Certificate{
SerialNumber: serialNumber,
Expand Down
41 changes: 37 additions & 4 deletions lib/certgen/certgen_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package certgen

import (
"bytes"
"crypto"
"crypto/sha256"
"crypto/x509"
Expand Down Expand Up @@ -215,6 +216,22 @@ AAAECdSciYZnODYp2QC0s838bYh8d2XEOuvBOqcOEA6MUjL8gKfkOxEiNHgbIpVQ+5xYns
Df7tMqg18r8iaCVRzqyFAAAAHWN2aWVjY29AY3ZpZWNjby0tTWFjQm9va1BybzE1
-----END OPENSSH PRIVATE KEY-----`

// We should not be using p224 keys except for testing
// openssl ecparam -name secp224r1 -genkey
const testP224Privatekey = `-----BEGIN EC PRIVATE KEY-----
MGgCAQEEHNBN+rQ+YDZ27lRc6tHu5myU+kq8Tetzodw4bfOgBwYFK4EEACGhPAM6
AARWr9bjMJaYzHyQjD2za224ohGmBg6/6H5pomxWY8fkAfZy/DmjRRCD72pX86xp
PSDtPZDi9/ao4g==
-----END EC PRIVATE KEY-----`

// The tranformation requires the full information of the private key
//
// openssl ec -in private.ec.key -pubout
const testP224PublicKey = `-----BEGIN PUBLIC KEY-----
ME4wEAYHKoZIzj0CAQYFK4EEACEDOgAEVq/W4zCWmMx8kIw9s2ttuKIRpgYOv+h+
aaJsVmPH5AH2cvw5o0UQg+9qV/OsaT0g7T2Q4vf2qOI=
-----END PUBLIC KEY-----`

const testDuration = time.Duration(120 * time.Second)

// SSSD tests do require some setup... in this case we do some checks to ensure
Expand Down Expand Up @@ -541,6 +558,8 @@ func TestGenx509CertGoodWithRealm(t *testing.T) {
// GenSelfSignedCACert
func TestGenSelfSignedCACertGood(t *testing.T) {
validPemKeys := []string{testSignerPrivateKey, pkcs8ecPrivateKey, pkcs8Ed25519PrivateKey}
publcKeyPems := []string{testUserPEMPublicKey, testP224PublicKey}

for _, signerPem := range validPemKeys {
caPriv, err := GetSignerFromPEMBytes([]byte(signerPem))
if err != nil {
Expand All @@ -557,16 +576,30 @@ func TestGenSelfSignedCACertGood(t *testing.T) {
}
t.Logf("got '%s'", pemCert)

// Now we use it to generate a user Cert
userPub, err := getPubKeyFromPem(testUserPEMPublicKey)
derCaCert2, err := GenSelfSignedCACert("some hostname", "some organization", caPriv)
if err != nil {
t.Fatal(err)
}
_, err = GenUserX509Cert("username", userPub, cert, caPriv, nil,
testDuration, nil, nil, nil, testlogger.New(t))
cacert2, _, err := derBytesCertToCertAndPem(derCaCert2)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(cert.RawSubject, cacert2.RawSubject) {
t.Fatalf("subjects across generations should match")
}

// Now we use it to generate a user Cert
for _, publicPem := range publcKeyPems {
userPub, err := getPubKeyFromPem(publicPem)
if err != nil {
t.Fatal(err)
}
_, err = GenUserX509Cert("username", userPub, cert, caPriv, nil,
testDuration, nil, nil, nil, testlogger.New(t))
if err != nil {
t.Fatal(err)
}
}
//t.Logf("got '%s'", certString)
}

Expand Down

0 comments on commit cc403a7

Please sign in to comment.