Extract receiver for keyset item addition

This commit is contained in:
John Gardiner Myers 2021-04-17 19:24:47 -07:00
parent 3793c92b94
commit 9861009759
4 changed files with 164 additions and 12 deletions

View File

@ -132,20 +132,15 @@ func RunCreateKeypairCa(ctx context.Context, f *util.Factory, out io.Writer, opt
return fmt.Errorf("error loading certificate %q: %v", options.CertPath, err)
}
serialString := cert.Certificate.SerialNumber.String()
ki := &fi.KeysetItem{
Id: serialString,
Certificate: cert,
PrivateKey: privateKey,
keyset := &fi.Keyset{
Items: map[string]*fi.KeysetItem{},
}
err = keyset.AddItem(cert, privateKey)
if err != nil {
return err
}
err = keyStore.StoreKeyset(fi.CertificateIDCA, &fi.Keyset{
LegacyFormat: false,
Items: map[string]*fi.KeysetItem{
serialString: ki,
},
Primary: ki,
})
err = keyStore.StoreKeyset(fi.CertificateIDCA, keyset)
if err != nil {
return fmt.Errorf("error storing user provided keys %q %q: %v", options.CertPath, options.PrivateKeyPath, err)
}

View File

@ -68,6 +68,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"ca_test.go",
"dryruntarget_test.go",
"files_test.go",
"vfs_castore_test.go",
@ -79,5 +80,6 @@ go_test(
"//pkg/pki:go_default_library",
"//util/pkg/vfs:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
],
)

View File

@ -24,6 +24,7 @@ import (
"math/big"
"sort"
"strconv"
"time"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/pki"
@ -226,3 +227,28 @@ func (k *Keyset) ToPublicKeyBytes() ([]byte, error) {
}
return buf.Bytes(), nil
}
// AddItem adds an item to the keyset
func (k *Keyset) AddItem(cert *pki.Certificate, privateKey *pki.PrivateKey) error {
if cert == nil {
return fmt.Errorf("no certificate provided")
}
if privateKey == nil {
return fmt.Errorf("no private key provided")
}
// Make sure any subsequently created certificates will have ids that compare higher.
idNumber := pki.BuildPKISerial(time.Now().UnixNano())
if cert.Certificate.SerialNumber.Cmp(idNumber) <= 0 {
idNumber = cert.Certificate.SerialNumber
}
ki := &KeysetItem{
Id: idNumber.String(),
Certificate: cert,
PrivateKey: privateKey,
}
k.Items[ki.Id] = ki
k.Primary = ki
return nil
}

129
upup/pkg/fi/ca_test.go Normal file
View File

@ -0,0 +1,129 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fi_test
import (
"math/big"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/kops/pkg/pki"
"k8s.io/kops/upup/pkg/fi"
)
const certData = "-----BEGIN CERTIFICATE-----\nMIIC+DCCAeCgAwIBAgIMFnbTyckBfEgW0qf0MA0GCSqGSIb3DQEBCwUAMBgxFjAU\nBgNVBAMTDWNuPWt1YmVybmV0ZXMwHhcNMjEwNDE2MDI0NjE5WhcNMzEwNDE2MDI0\nNjE5WjAYMRYwFAYDVQQDEw1jbj1rdWJlcm5ldGVzMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEA4JwpEprZ5n8RIEt6jT2lAh+UDgRgx/4px21gjgywQivY\nHVxHAZexVb/E9pBa9Q2G9B1Q7TCO7YsUVRQy4JMDZVt+McFnWVwexnqBYFNcVjkE\nmDgAgvCYGE0P9d/RwRL4KuLHo+u6fv7P0jXMN+CpOxyLhYZZNa0ZOZDHsSiJSQSj\n9WGFGHrbCf0KVDpKieR1uBqHrRO+mLR5zkX2L58m74kjK4dsBhmjeq/7OAoTmiG2\nQgJ/P2IjyhiA2mRqY+hl55lwEUV/0yHYEkJC8LdGkwwZz2eF77aSPGmi/A2CSKgM\nwDTx9m+P7jcpWreYw6NG9BueGoDIve/tgFKwvVFF6QIDAQABo0IwQDAOBgNVHQ8B\nAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVOJ/Z21wnbF5Kjsi\nJFdZL/rKHJ4wDQYJKoZIhvcNAQELBQADggEBABWm3zNEiAO+HxfT+WYUhS/ot1Rf\nwzQUPmFR+1GGdXxOam4dMQ0X9uJsE5PtNw7kg9ja+jkUuharSXraueu6IbcRCXQ8\nycnjmbhcPdvH8dhQAB+2Y1xyf/olWan7NU98fwwWk3ubX1aUaoBbXJW9IqkmRG6K\nZVTnz0yGdQfqZyZbl48WfIQ3W7qsAnsSYSrhUWNNOHgy6NQRxpgzGohYFAUprFqc\n8Dm02rzpNwe+ZDOInm05UUOblsdeHYrRetfvhnYJl/CEPGAdJGnOjLMjr7V85y4a\n41XKFsjMo2ztvNdLmYiw0dfar4WSdK/AKFzUXEPRwjCe5xMtsMOIkyJtvxw=\n-----END CERTIFICATE-----\n"
const tooBigSerialCertData = "-----BEGIN CERTIFICATE-----\nMIIC2DCCAcCgAwIBAgIRALJXAkVj964tq67wMSI8oJQwDQYJKoZIhvcNAQELBQAw\nFTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0xNzEyMjcyMzUyNDBaFw0yNzEyMjcy\nMzUyNDBaMBUxEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUA\nA4IBDwAwggEKAoIBAQDgnCkSmtnmfxEgS3qNPaUCH5QOBGDH/inHbWCODLBCK9gd\nXEcBl7FVv8T2kFr1DYb0HVDtMI7tixRVFDLgkwNlW34xwWdZXB7GeoFgU1xWOQSY\nOACC8JgYTQ/139HBEvgq4sej67p+/s/SNcw34Kk7HIuFhlk1rRk5kMexKIlJBKP1\nYYUYetsJ/QpUOkqJ5HW4GoetE76YtHnORfYvnybviSMrh2wGGaN6r/s4ChOaIbZC\nAn8/YiPKGIDaZGpj6GXnmXARRX/TIdgSQkLwt0aTDBnPZ4XvtpI8aaL8DYJIqAzA\nNPH2b4/uNylat5jDo0b0G54agMi97+2AUrC9UUXpAgMBAAGjIzAhMA4GA1UdDwEB\n/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBVGR2r\nhzXzRMU5wriPQAJScszNORvoBpXfZoZ09FIupudFxBVU3d4hV9StKnQgPSGA5XQO\nHE97+BxJDuA/rB5oBUsMBjc7y1cde/T6hmi3rLoEYBSnSudCOXJE4G9/0f8byAJe\nrN8+No1r2VgZvZh6p74TEkXv/l3HBPWM7IdUV0HO9JDhSgOVF1fyQKJxRuLJR8jt\nO6mPH2UX0vMwVa4jvwtkddqk2OAdYQvH9rbDjjbzaiW0KnmdueRo92KHAN7BsDZy\nVpXHpqo1Kzg7D3fpaXCf5si7lqqrdJVXH4JC72zxsPehqgi8eIuqOBkiDWmRxAxh\n8yGeRx9AbknHh4Ia\n-----END CERTIFICATE-----\n"
const privatekeyData = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA4JwpEprZ5n8RIEt6jT2lAh+UDgRgx/4px21gjgywQivYHVxH\nAZexVb/E9pBa9Q2G9B1Q7TCO7YsUVRQy4JMDZVt+McFnWVwexnqBYFNcVjkEmDgA\ngvCYGE0P9d/RwRL4KuLHo+u6fv7P0jXMN+CpOxyLhYZZNa0ZOZDHsSiJSQSj9WGF\nGHrbCf0KVDpKieR1uBqHrRO+mLR5zkX2L58m74kjK4dsBhmjeq/7OAoTmiG2QgJ/\nP2IjyhiA2mRqY+hl55lwEUV/0yHYEkJC8LdGkwwZz2eF77aSPGmi/A2CSKgMwDTx\n9m+P7jcpWreYw6NG9BueGoDIve/tgFKwvVFF6QIDAQABAoIBAA0ktjaTfyrAxsTI\nBezb7Zr5NBW55dvuII299cd6MJo+rI/TRYhvUv48kY8IFXp/hyUjzgeDLunxmIf9\n/Zgsoic9Ol44/g45mMduhcGYPzAAeCdcJ5OB9rR9VfDCXyjYLlN8H8iU0734tTqM\n0V13tQ9zdSqkGPZOIcq/kR/pylbOZaQMe97BTlsAnOMSMKDgnftY4122Lq3GYy+t\nvpr+bKVaQZwvkLoSU3rECCaKaghgwCyX7jft9aEkhdJv+KlwbsGY6WErvxOaLWHd\ncuMQjGapY1Fa/4UD00mvrA260NyKfzrp6+P46RrVMwEYRJMIQ8YBAk6N6Hh7dc0G\n8Z6i1m0CgYEA9HeCJR0TSwbIQ1bDXUrzpftHuidG5BnSBtax/ND9qIPhR/FBW5nj\n22nwLc48KkyirlfIULd0ae4qVXJn7wfYcuX/cJMLDmSVtlM5Dzmi/91xRiFgIzx1\nAsbBzaFjISP2HpSgL+e9FtSXaaqeZVrflitVhYKUpI/AKV31qGHf04sCgYEA6zTV\n99Sb49Wdlns5IgsfnXl6ToRttB18lfEKcVfjAM4frnkk06JpFAZeR+9GGKUXZHqs\nz2qcplw4d/moCC6p3rYPBMLXsrGNEUFZqBlgz72QA6BBq3X0Cg1Bc2ZbK5VIzwkg\nST2SSux6ccROfgULmN5ZiLOtdUKNEZpFF3i3qtsCgYADT/s7dYFlatobz3kmMnXK\nsfTu2MllHdRys0YGHu7Q8biDuQkhrJwhxPW0KS83g4JQym+0aEfzh36bWcl+u6R7\nKhKj+9oSf9pndgk345gJz35RbPJYh+EuAHNvzdgCAvK6x1jETWeKf6btj5pF1U1i\nQ4QNIw/QiwIXjWZeubTGsQKBgQCbduLu2rLnlyyAaJZM8DlHZyH2gAXbBZpxqU8T\nt9mtkJDUS/KRiEoYGFV9CqS0aXrayVMsDfXY6B/S/UuZjO5u7LtklDzqOf1aKG3Q\ndGXPKibknqqJYH+bnUNjuYYNerETV57lijMGHuSYCf8vwLn3oxBfERRX61M/DU8Z\nworz/QKBgQDCTJI2+jdXg26XuYUmM4XXfnocfzAXhXBULt1nENcogNf1fcptAVtu\nBAiz4/HipQKqoWVUYmxfgbbLRKKLK0s0lOWKbYdVjhEm/m2ZU8wtXTagNwkIGoyq\nY/C1Lox4f1ROJnCjc/hfcOjcxX5M8A8peecHWlVtUPKTJgxQ7oMKcw==\n-----END RSA PRIVATE KEY-----\n"
func TestAddItem(t *testing.T) {
cert, _ := pki.ParsePEMCertificate([]byte(certData))
tooBigSerialCert, _ := pki.ParsePEMCertificate([]byte(tooBigSerialCertData))
privateKey, _ := pki.ParsePEMPrivateKey([]byte(privatekeyData))
type expectedItems []struct {
validateId func(t *testing.T, id string)
cert *pki.Certificate
privateKey *pki.PrivateKey
}
tests := []struct {
name string
keyset fi.Keyset
cert *pki.Certificate
privateKey *pki.PrivateKey
expectedItems expectedItems
expectedPrimary *pki.PrivateKey
expectedError string
}{
{
name: "first",
keyset: fi.Keyset{
Items: map[string]*fi.KeysetItem{},
},
cert: cert,
privateKey: privateKey,
expectedItems: expectedItems{
{
cert: cert,
privateKey: privateKey,
},
},
expectedPrimary: privateKey,
},
{
name: "BigSerial",
keyset: fi.Keyset{
Items: map[string]*fi.KeysetItem{},
},
cert: tooBigSerialCert,
privateKey: privateKey,
expectedItems: expectedItems{
{
validateId: func(t *testing.T, id string) {
version, ok := big.NewInt(0).SetString(id, 10)
require.True(t, ok, "parses as integer")
if version.Cmp(pki.BuildPKISerial(time.Now().UnixNano())) > 0 {
t.Errorf("id %q larger than serial for current time", id)
}
},
cert: tooBigSerialCert,
privateKey: privateKey,
},
},
expectedPrimary: privateKey,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.keyset.AddItem(tc.cert, tc.privateKey)
if tc.expectedError != "" {
assert.EqualError(t, err, tc.expectedError)
return
}
assert.NoError(t, err)
assert.Equal(t, tc.expectedPrimary, tc.keyset.Primary.PrivateKey, "primary key")
expected:
for _, expected := range tc.expectedItems {
for id, item := range tc.keyset.Items {
if (expected.cert != nil && expected.cert == item.Certificate) ||
expected.privateKey != nil && expected.privateKey == item.PrivateKey {
assert.Same(t, expected.cert, item.Certificate, "item %s", id)
assert.Same(t, expected.privateKey, item.PrivateKey, "item %s", id)
if expected.validateId == nil {
assert.Equal(t, expected.cert.Certificate.SerialNumber.String(), id, "id")
} else {
expected.validateId(t, id)
}
delete(tc.keyset.Items, id)
continue expected
}
}
if expected.cert != nil {
t.Errorf("did not find expected item %q", expected.cert.Certificate.SerialNumber)
} else {
t.Errorf("did not find expected key %q", expected.privateKey)
}
}
for id := range tc.keyset.Items {
t.Errorf("unexpected item %q", id)
}
})
}
}