github.com/letsencrypt/boulder@v0.20251208.0/core/objects_test.go (about)

     1  package core
     2  
     3  import (
     4  	"crypto/rsa"
     5  	"encoding/json"
     6  	"math/big"
     7  	"net/netip"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/go-jose/go-jose/v4"
    12  
    13  	"github.com/letsencrypt/boulder/test"
    14  )
    15  
    16  func TestExpectedKeyAuthorization(t *testing.T) {
    17  	ch := Challenge{Token: "hi"}
    18  	jwk1 := &jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(1234), E: 1234}}
    19  	jwk2 := &jose.JSONWebKey{Key: &rsa.PublicKey{N: big.NewInt(5678), E: 5678}}
    20  
    21  	ka1, err := ch.ExpectedKeyAuthorization(jwk1)
    22  	test.AssertNotError(t, err, "Failed to calculate expected key authorization 1")
    23  	ka2, err := ch.ExpectedKeyAuthorization(jwk2)
    24  	test.AssertNotError(t, err, "Failed to calculate expected key authorization 2")
    25  
    26  	expected1 := "hi.sIMEyhkWCCSYqDqZqPM1bKkvb5T9jpBOb7_w5ZNorF4"
    27  	expected2 := "hi.FPoiyqWPod2T0fKqkPI1uXPYUsRK1DSyzsQsv0oMuGg"
    28  	if ka1 != expected1 {
    29  		t.Errorf("Incorrect ka1. Expected [%s], got [%s]", expected1, ka1)
    30  	}
    31  	if ka2 != expected2 {
    32  		t.Errorf("Incorrect ka2. Expected [%s], got [%s]", expected2, ka2)
    33  	}
    34  }
    35  
    36  func TestRecordSanityCheckOnUnsupportedChallengeType(t *testing.T) {
    37  	rec := []ValidationRecord{
    38  		{
    39  			URL:               "http://localhost/test",
    40  			Hostname:          "localhost",
    41  			Port:              "80",
    42  			AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
    43  			AddressUsed:       netip.MustParseAddr("127.0.0.1"),
    44  			ResolverAddrs:     []string{"eastUnboundAndDown"},
    45  		},
    46  	}
    47  
    48  	chall := Challenge{Type: "obsoletedChallenge", ValidationRecord: rec}
    49  	test.Assert(t, !chall.RecordsSane(), "Record with unsupported challenge type should not be sane")
    50  }
    51  
    52  func TestChallengeSanityCheck(t *testing.T) {
    53  	// Make a temporary account key
    54  	var accountKey *jose.JSONWebKey
    55  	err := json.Unmarshal([]byte(`{
    56      "kty":"RSA",
    57      "n":"yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ",
    58      "e":"AQAB"
    59    }`), &accountKey)
    60  	test.AssertNotError(t, err, "Error unmarshaling JWK")
    61  
    62  	types := []AcmeChallenge{ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01, ChallengeTypeDNSAccount01}
    63  	for _, challengeType := range types {
    64  		chall := Challenge{
    65  			Type:   challengeType,
    66  			Status: StatusInvalid,
    67  		}
    68  		test.AssertError(t, chall.CheckPending(), "CheckConsistencyForClientOffer didn't return an error")
    69  
    70  		chall.Status = StatusPending
    71  		test.AssertError(t, chall.CheckPending(), "CheckConsistencyForClientOffer didn't return an error")
    72  
    73  		chall.Token = "KQqLsiS5j0CONR_eUXTUSUDNVaHODtc-0pD6ACif7U4"
    74  		test.AssertNotError(t, chall.CheckPending(), "CheckConsistencyForClientOffer returned an error")
    75  	}
    76  }
    77  
    78  func TestJSONBufferUnmarshal(t *testing.T) {
    79  	testStruct := struct {
    80  		Buffer JSONBuffer
    81  	}{}
    82  
    83  	notValidBase64 := []byte(`{"Buffer":"!!!!"}`)
    84  	err := json.Unmarshal(notValidBase64, &testStruct)
    85  	test.Assert(t, err != nil, "Should have choked on invalid base64")
    86  }
    87  
    88  func TestAuthorizationSolvedBy(t *testing.T) {
    89  	validHTTP01 := HTTPChallenge01("")
    90  	validHTTP01.Status = StatusValid
    91  	validDNS01 := DNSChallenge01("")
    92  	validDNS01.Status = StatusValid
    93  	testCases := []struct {
    94  		Name           string
    95  		Authz          Authorization
    96  		ExpectedResult AcmeChallenge
    97  		ExpectedError  string
    98  	}{
    99  		// An authz with no challenges should return nil
   100  		{
   101  			Name:          "No challenges",
   102  			Authz:         Authorization{},
   103  			ExpectedError: "authorization has no challenges",
   104  		},
   105  		// An authz with all non-valid challenges should return nil
   106  		{
   107  			Name: "All non-valid challenges",
   108  			Authz: Authorization{
   109  				Challenges: []Challenge{HTTPChallenge01(""), DNSChallenge01("")},
   110  			},
   111  			ExpectedError: "authorization not solved by any challenge",
   112  		},
   113  		// An authz with one valid HTTP01 challenge amongst other challenges should
   114  		// return the HTTP01 challenge
   115  		{
   116  			Name: "Valid HTTP01 challenge",
   117  			Authz: Authorization{
   118  				Challenges: []Challenge{HTTPChallenge01(""), validHTTP01, DNSChallenge01("")},
   119  			},
   120  			ExpectedResult: ChallengeTypeHTTP01,
   121  		},
   122  		// An authz with both a valid HTTP01 challenge and a valid DNS01 challenge
   123  		// among other challenges should return whichever valid challenge is first
   124  		// (in this case DNS01)
   125  		{
   126  			Name: "Valid HTTP01 and DNS01 challenge",
   127  			Authz: Authorization{
   128  				Challenges: []Challenge{validDNS01, HTTPChallenge01(""), validHTTP01, DNSChallenge01("")},
   129  			},
   130  			ExpectedResult: ChallengeTypeDNS01,
   131  		},
   132  	}
   133  
   134  	for _, tc := range testCases {
   135  		t.Run(tc.Name, func(t *testing.T) {
   136  			result, err := tc.Authz.SolvedBy()
   137  			if tc.ExpectedError != "" {
   138  				test.AssertEquals(t, err.Error(), tc.ExpectedError)
   139  			}
   140  			if tc.ExpectedResult != "" {
   141  				test.AssertEquals(t, result, tc.ExpectedResult)
   142  			}
   143  		})
   144  	}
   145  }
   146  
   147  func TestChallengeStringID(t *testing.T) {
   148  	ch := Challenge{
   149  		Token: "asd",
   150  		Type:  ChallengeTypeDNS01,
   151  	}
   152  	test.AssertEquals(t, ch.StringID(), "iFVMwA")
   153  	ch.Type = ChallengeTypeHTTP01
   154  	test.AssertEquals(t, ch.StringID(), "0Gexug")
   155  	ch.Type = ChallengeTypeDNSAccount01
   156  	test.AssertEquals(t, ch.StringID(), "8z2wSg")
   157  }
   158  
   159  func TestFindChallengeByType(t *testing.T) {
   160  	authz := Authorization{
   161  		Challenges: []Challenge{
   162  			{Token: "woo", Type: ChallengeTypeDNS01},
   163  			{Token: "woo", Type: ChallengeTypeHTTP01},
   164  		},
   165  	}
   166  	test.AssertEquals(t, 0, authz.FindChallengeByStringID(authz.Challenges[0].StringID()))
   167  	test.AssertEquals(t, 1, authz.FindChallengeByStringID(authz.Challenges[1].StringID()))
   168  	test.AssertEquals(t, -1, authz.FindChallengeByStringID("hello"))
   169  }
   170  
   171  func TestRenewalInfoSuggestedWindowIsWithin(t *testing.T) {
   172  	now := time.Now().UTC()
   173  	window := SuggestedWindow{
   174  		Start: now,
   175  		End:   now.Add(time.Hour),
   176  	}
   177  
   178  	// Exactly the beginning, inclusive of the first nanosecond.
   179  	test.Assert(t, window.IsWithin(now), "Start of window should be within the window")
   180  
   181  	// Exactly the middle.
   182  	test.Assert(t, window.IsWithin(now.Add(time.Minute*30)), "Middle of window should be within the window")
   183  
   184  	// Exactly the end time.
   185  	test.Assert(t, !window.IsWithin(now.Add(time.Hour)), "End of window should be outside the window")
   186  
   187  	// Exactly the end of the window.
   188  	test.Assert(t, window.IsWithin(now.Add(time.Hour-time.Nanosecond)), "Should be just inside the window")
   189  
   190  	// Just before the first nanosecond.
   191  	test.Assert(t, !window.IsWithin(now.Add(-time.Nanosecond)), "Before the window should not be within the window")
   192  }