Skip to content
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

Added additional tests for CA implementations and OIDC #602

Merged
merged 2 commits into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 48 additions & 0 deletions pkg/ca/ephemeralca/ephemeral_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2022 The Sigstore 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 ephemeralca

import (
"crypto/x509"
"testing"
"time"

"github.com/sigstore/sigstore/pkg/cryptoutils"
)

func TestNewEphemeralCA(t *testing.T) {
ca, err := NewEphemeralCA()
if err != nil {
t.Fatalf("unexpected error generating ephemeral CA: %v", err)
}
if ca.RootCA == nil {
t.Fatalf("ca not set up")
}
if ca.RootCA.NotAfter.Sub(ca.RootCA.NotBefore) < time.Hour*24*365*10 {
t.Fatalf("expected CA to have 10 year lifetime, got %v", ca.RootCA.NotAfter.Sub(ca.RootCA.NotBefore))
}
if !ca.RootCA.IsCA {
t.Fatalf("ca does not have IsCA bit set")
}
if ca.RootCA.MaxPathLen != 1 {
t.Fatalf("expected CA with path length of 1, got %d", ca.RootCA.MaxPathLen)
}
if ca.RootCA.KeyUsage != x509.KeyUsageCertSign|x509.KeyUsageCRLSign {
t.Fatalf("expected cert sign and crl sign key usage")
}
if err := cryptoutils.EqualKeys(ca.PrivKey.Public(), ca.RootCA.PublicKey); err != nil {
t.Fatalf("expected verification key and certificate key to match")
}
}
119 changes: 119 additions & 0 deletions pkg/ca/x509ca/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2022 The Sigstore 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 x509ca

import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"reflect"
"testing"
"time"
)

// cannot use ChallengeResult due to import cycle
type testPrincipal struct {
}

func (t *testPrincipal) Name(_ context.Context) string {
return "test"
}
func (t *testPrincipal) Embed(_ context.Context, cert *x509.Certificate) error {
cert.EmailAddresses = []string{"test@example.com"}
return nil
}

func TestMakeX509(t *testing.T) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("unexpected error generating key: %v", err)
}
cert, err := MakeX509(context.TODO(), &testPrincipal{}, key.Public())
if err != nil {
t.Fatalf("unexpected error calling MakeX509: %v", err)
}
if cert.SerialNumber == nil {
t.Fatalf("expected serial number")
}
if cert.NotAfter.Sub(cert.NotBefore) < time.Minute*10 {
t.Fatalf("expected CA to have 10 minute lifetime, got %v", cert.NotAfter.Sub(cert.NotBefore))
}
if len(cert.SubjectKeyId) == 0 {
t.Fatalf("expected subject key ID")
}
if len(cert.ExtKeyUsage) != 1 || cert.ExtKeyUsage[0] != x509.ExtKeyUsageCodeSigning {
t.Fatalf("expected code signing extended key usage, got %v", cert.ExtKeyUsage)
}
if cert.KeyUsage != x509.KeyUsageDigitalSignature {
t.Fatalf("expected digital signature key usage, got %v", cert.KeyUsage)
}
// test that Embed is called
if len(cert.EmailAddresses) != 1 {
t.Fatalf("expected email in subject alt name, got %v", cert.EmailAddresses)
}
}

func TestRootAndCreateCertificate(t *testing.T) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("unexpected error generating key: %v", err)
}
cert, err := MakeX509(context.TODO(), &testPrincipal{}, key.Public())
if err != nil {
t.Fatalf("unexpected error calling MakeX509: %v", err)
}
// sign certificate to populate with expected values
caBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, key.Public(), key)
if err != nil {
t.Fatalf("unexpected error signing certificate: %v", err)
}
ca := &X509CA{
PrivKey: key,
}
ca.RootCA, err = x509.ParseCertificate(caBytes)
if err != nil {
t.Fatalf("unexpected error parsing certificate, got %v", err)
}

pemRoot, err := ca.Root(context.TODO())
if err != nil {
t.Fatalf("unexpected error generating root: %v", err)
}
block, rest := pem.Decode(pemRoot)
if len(rest) > 0 {
t.Fatalf("expected no additional PEM blocks")
}
if block.Type != "CERTIFICATE" {
t.Fatalf("expected CERTIFICATE type, got %s", block.Type)
}
if !reflect.DeepEqual(ca.RootCA.Raw, block.Bytes) {
t.Fatalf("raw certificates were not equal")
}

// create a certificate that chains up to this CA
csc, err := ca.CreateCertificate(context.TODO(), &testPrincipal{}, key.Public())
if err != nil {
t.Fatalf("unexpected error creating certificate: %v", err)
}
if csc.FinalCertificate == nil {
t.Fatalf("expected certificate in structure")
}
if len(csc.FinalChain) != 1 {
t.Fatalf("expected 1 certificate in chain, got %d", len(csc.FinalChain))
}
}
41 changes: 40 additions & 1 deletion pkg/oauthflow/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package oauthflow
import (
"errors"
"reflect"
"strings"
"testing"
"unsafe"

Expand All @@ -35,7 +36,7 @@ func updateIDToken(idToken *oidc.IDToken, fieldName string, data []byte) {
*realPointer = data
}

func TestTokenWithClaims(t *testing.T) {
func TestEmailFromIDToken(t *testing.T) {
tests := []struct {
name string
inputClaims []byte
Expand Down Expand Up @@ -86,3 +87,41 @@ func TestTokenWithClaims(t *testing.T) {
})
}
}

func TestIssuerFromIDToken(t *testing.T) {
expectedIss := "issuer"
idToken := &oidc.IDToken{Issuer: expectedIss}

// Test with no claims path
iss, err := IssuerFromIDToken(idToken, "")
if err != nil {
t.Fatalf("unexpected error generating issuer: %v", err)
}
if iss != expectedIss {
t.Fatalf("unexpected issuer, expected %s, got %s", expectedIss, iss)
}

// append additional claims
otherExpectedIss := "otherIssuer"
updateIDToken(idToken, "claims", []byte(`{"other_issuer":"otherIssuer"}`))
iss, err = IssuerFromIDToken(idToken, "$.other_issuer")
if err != nil {
t.Fatalf("unexpected error generating issuer: %v", err)
}
if iss != otherExpectedIss {
t.Fatalf("unexpected issuer, expected %s, got %s", otherExpectedIss, iss)
}

// failure with invalid claim path
_, err = IssuerFromIDToken(idToken, "$.invalid")
if err == nil || !strings.Contains(err.Error(), "unknown key invalid") {
t.Fatalf("expected error fetching invalid key, got %v", err)
}

// failure with invalid claims
updateIDToken(idToken, "claims", []byte(`{`))
_, err = IssuerFromIDToken(idToken, "$.other_issuer")
if err == nil || !strings.Contains(err.Error(), "unexpected end of JSON input") {
t.Fatalf("expected error with malformed ID token, got %v", err)
}
}