boulder/core/objects_test.go

191 lines
6.2 KiB
Go

package core
import (
"crypto/rsa"
"encoding/json"
"math/big"
"net/netip"
"testing"
"time"
"github.com/go-jose/go-jose/v4"
"github.com/letsencrypt/boulder/test"
)
func TestExpectedKeyAuthorization(t *testing.T) {
ch := Challenge{Token: "hi"}
jwk1 := &jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1234), E: 1234}}
jwk2 := &jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(5678), E: 5678}}
ka1, err := ch.ExpectedKeyAuthorization(jwk1)
test.AssertNotError(t, err, "Failed to calculate expected key authorization 1")
ka2, err := ch.ExpectedKeyAuthorization(jwk2)
test.AssertNotError(t, err, "Failed to calculate expected key authorization 2")
expected1 := "hi.sIMEyhkWCCSYqDqZqPM1bKkvb5T9jpBOb7_w5ZNorF4"
expected2 := "hi.FPoiyqWPod2T0fKqkPI1uXPYUsRK1DSyzsQsv0oMuGg"
if ka1 != expected1 {
t.Errorf("Incorrect ka1. Expected [%s], got [%s]", expected1, ka1)
}
if ka2 != expected2 {
t.Errorf("Incorrect ka2. Expected [%s], got [%s]", expected2, ka2)
}
}
func TestRecordSanityCheckOnUnsupportedChallengeType(t *testing.T) {
rec := []ValidationRecord{
{
URL: "http://localhost/test",
DnsName: "localhost",
Port: "80",
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
AddressUsed: netip.MustParseAddr("127.0.0.1"),
ResolverAddrs: []string{"eastUnboundAndDown"},
},
}
chall := Challenge{Type: "obsoletedChallenge", ValidationRecord: rec}
test.Assert(t, !chall.RecordsSane(), "Record with unsupported challenge type should not be sane")
}
func TestChallengeSanityCheck(t *testing.T) {
// Make a temporary account key
var accountKey *jose.JSONWebKey
err := json.Unmarshal([]byte(`{
"kty":"RSA",
"n":"yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ",
"e":"AQAB"
}`), &accountKey)
test.AssertNotError(t, err, "Error unmarshaling JWK")
types := []AcmeChallenge{ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01}
for _, challengeType := range types {
chall := Challenge{
Type: challengeType,
Status: StatusInvalid,
}
test.AssertError(t, chall.CheckPending(), "CheckConsistencyForClientOffer didn't return an error")
chall.Status = StatusPending
test.AssertError(t, chall.CheckPending(), "CheckConsistencyForClientOffer didn't return an error")
chall.Token = "KQqLsiS5j0CONR_eUXTUSUDNVaHODtc-0pD6ACif7U4"
test.AssertNotError(t, chall.CheckPending(), "CheckConsistencyForClientOffer returned an error")
}
}
func TestJSONBufferUnmarshal(t *testing.T) {
testStruct := struct {
Buffer JSONBuffer
}{}
notValidBase64 := []byte(`{"Buffer":"!!!!"}`)
err := json.Unmarshal(notValidBase64, &testStruct)
test.Assert(t, err != nil, "Should have choked on invalid base64")
}
func TestAuthorizationSolvedBy(t *testing.T) {
validHTTP01 := HTTPChallenge01("")
validHTTP01.Status = StatusValid
validDNS01 := DNSChallenge01("")
validDNS01.Status = StatusValid
testCases := []struct {
Name string
Authz Authorization
ExpectedResult AcmeChallenge
ExpectedError string
}{
// An authz with no challenges should return nil
{
Name: "No challenges",
Authz: Authorization{},
ExpectedError: "authorization has no challenges",
},
// An authz with all non-valid challenges should return nil
{
Name: "All non-valid challenges",
Authz: Authorization{
Challenges: []Challenge{HTTPChallenge01(""), DNSChallenge01("")},
},
ExpectedError: "authorization not solved by any challenge",
},
// An authz with one valid HTTP01 challenge amongst other challenges should
// return the HTTP01 challenge
{
Name: "Valid HTTP01 challenge",
Authz: Authorization{
Challenges: []Challenge{HTTPChallenge01(""), validHTTP01, DNSChallenge01("")},
},
ExpectedResult: ChallengeTypeHTTP01,
},
// An authz with both a valid HTTP01 challenge and a valid DNS01 challenge
// among other challenges should return whichever valid challenge is first
// (in this case DNS01)
{
Name: "Valid HTTP01 and DNS01 challenge",
Authz: Authorization{
Challenges: []Challenge{validDNS01, HTTPChallenge01(""), validHTTP01, DNSChallenge01("")},
},
ExpectedResult: ChallengeTypeDNS01,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
result, err := tc.Authz.SolvedBy()
if tc.ExpectedError != "" {
test.AssertEquals(t, err.Error(), tc.ExpectedError)
}
if tc.ExpectedResult != "" {
test.AssertEquals(t, result, tc.ExpectedResult)
}
})
}
}
func TestChallengeStringID(t *testing.T) {
ch := Challenge{
Token: "asd",
Type: ChallengeTypeDNS01,
}
test.AssertEquals(t, ch.StringID(), "iFVMwA")
ch.Type = ChallengeTypeHTTP01
test.AssertEquals(t, ch.StringID(), "0Gexug")
}
func TestFindChallengeByType(t *testing.T) {
authz := Authorization{
Challenges: []Challenge{
{Token: "woo", Type: ChallengeTypeDNS01},
{Token: "woo", Type: ChallengeTypeHTTP01},
},
}
test.AssertEquals(t, 0, authz.FindChallengeByStringID(authz.Challenges[0].StringID()))
test.AssertEquals(t, 1, authz.FindChallengeByStringID(authz.Challenges[1].StringID()))
test.AssertEquals(t, -1, authz.FindChallengeByStringID("hello"))
}
func TestRenewalInfoSuggestedWindowIsWithin(t *testing.T) {
now := time.Now().UTC()
window := SuggestedWindow{
Start: now,
End: now.Add(time.Hour),
}
// Exactly the beginning, inclusive of the first nanosecond.
test.Assert(t, window.IsWithin(now), "Start of window should be within the window")
// Exactly the middle.
test.Assert(t, window.IsWithin(now.Add(time.Minute*30)), "Middle of window should be within the window")
// Exactly the end time.
test.Assert(t, !window.IsWithin(now.Add(time.Hour)), "End of window should be outside the window")
// Exactly the end of the window.
test.Assert(t, window.IsWithin(now.Add(time.Hour-time.Nanosecond)), "Should be just inside the window")
// Just before the first nanosecond.
test.Assert(t, !window.IsWithin(now.Add(-time.Nanosecond)), "Before the window should not be within the window")
}