| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- package ike
- import (
- "bytes"
- "errors"
- "testing"
- "vocat/internal/vowifi"
- )
- func TestPayloadAndProposalWireRoundTrip(t *testing.T) {
- offered := proposal{
- Number: 1,
- Protocol: protocolIKE,
- Transforms: []transform{
- {Type: transformEncryption, ID: encryptionAESCBC, KeyLength: 128},
- {Type: transformPRF, ID: prfHMACSHA1},
- {Type: transformIntegrity, ID: integrityHMACSHA1_96},
- {Type: transformDH, ID: dhMODP1024},
- },
- }
- sa, err := marshalProposals([]proposal{offered})
- if err != nil {
- t.Fatalf("marshalProposals() error = %v", err)
- }
- first, wire, err := marshalPayloadChain([]payload{
- {Type: payloadSA, Body: sa},
- {Type: payloadNonce, Body: bytes.Repeat([]byte{0xaa}, 32)},
- })
- if err != nil {
- t.Fatalf("marshalPayloadChain() error = %v", err)
- }
- if first != payloadSA || len(wire) < 8 || wire[0] != payloadNonce {
- t.Fatalf("unexpected payload chain header: first=%d wire=%x", first, wire[:8])
- }
- decoded, err := parsePayloadChain(first, wire)
- if err != nil {
- t.Fatalf("parsePayloadChain() error = %v", err)
- }
- if len(decoded) != 2 || decoded[0].Type != payloadSA || decoded[1].Type != payloadNonce {
- t.Fatalf("decoded payload chain = %#v", decoded)
- }
- proposals, err := parseProposals(decoded[0].Body)
- if err != nil {
- t.Fatalf("parseProposals() error = %v", err)
- }
- if len(proposals) != 1 || len(proposals[0].Transforms) != 4 ||
- proposals[0].Transforms[0].KeyLength != 128 {
- t.Fatalf("decoded proposal = %#v", proposals)
- }
- }
- func TestInitialEAPOnlyAuthCarriesAPNIDrAndNotify(t *testing.T) {
- idi := payload{Type: payloadIDi, Body: []byte{3, 0, 0, 0, 'u'}}
- idr := payload{Type: payloadIDr, Body: []byte{2, 0, 0, 0, 'i', 'm', 's'}}
- payloads := buildInitialEAPOnlyAuth(
- idi,
- idr,
- []byte{1, 2, 3},
- dualStackTrafficSelectors(payloadTSi),
- dualStackTrafficSelectors(payloadTSr),
- )
- if len(payloads) != 7 || payloads[0].Type != payloadIDi || payloads[1].Type != payloadIDr {
- t.Fatalf("initial auth payload order = %#v", payloads)
- }
- if got := string(payloads[1].Body[4:]); got != "ims" || payloads[1].Body[0] != 2 {
- t.Fatalf("IDr = type %d value %q, want ID_FQDN ims", payloads[1].Body[0], got)
- }
- kind, data, err := parseNotify(payloads[2])
- if err != nil {
- t.Fatalf("parseNotify() error = %v", err)
- }
- if kind != notifyEAPOnlyAuth || len(data) != 0 {
- t.Fatalf("notify = %d/%x, want EAP_ONLY_AUTHENTICATION", kind, data)
- }
- for _, kind := range []uint8{payloadTSi, payloadTSr} {
- item, err := onePayload(payloads, kind)
- if err != nil {
- t.Fatalf("onePayload(%d) error = %v", kind, err)
- }
- selectors, err := parseTrafficSelectors(item)
- if err != nil {
- t.Fatalf("parseTrafficSelectors(%d) error = %v", kind, err)
- }
- if len(selectors) != 2 || selectors[0].StartIP.To4() == nil || selectors[1].StartIP.To4() != nil {
- t.Fatalf("dual-stack selectors = %#v", selectors)
- }
- }
- }
- func TestResponderIDrValidatorsSeparateEPDGAndAPN(t *testing.T) {
- epdg := payload{
- Type: payloadIDr,
- Body: append([]byte{2, 0, 0, 0}, []byte("epdg.epc.mnc015.mcc234.pub.3gppnetwork.org")...),
- }
- if err := validateFQDNIDr(epdg, "epdg.epc.mnc015.mcc234.pub.3gppnetwork.org", "initial ePDG"); err != nil {
- t.Fatalf("valid initial IDr rejected: %v", err)
- }
- apn := payload{Type: payloadIDr, Body: []byte{2, 0, 0, 0, 'i', 'm', 's'}}
- if err := validateFQDNIDr(apn, "ims", "final APN"); err != nil {
- t.Fatalf("valid final IDr rejected: %v", err)
- }
- wrongType := apn
- wrongType.Body = append([]byte(nil), apn.Body...)
- wrongType.Body[0] = 11
- if err := validateFQDNIDr(wrongType, "ims", "final APN"); err == nil {
- t.Fatal("non-ID_FQDN final IDr was accepted")
- }
- if err := validateFQDNIDr(epdg, "ims", "final APN"); err == nil {
- t.Fatal("ePDG identity was accepted as the APN identity")
- }
- }
- func TestFinalEAPResponderAUTHValidAndInvalidNeverAllowed(t *testing.T) {
- suite := legacyTestSuite()
- msk := bytes.Repeat([]byte{0x10}, 64)
- initialResponse := bytes.Repeat([]byte{0x20}, 96)
- initiatorNonce := bytes.Repeat([]byte{0x30}, 32)
- skpr := bytes.Repeat([]byte{0x40}, 20)
- idr := payload{Type: payloadIDr, Body: append([]byte{2, 0, 0, 0}, []byte("epdg.example")...)}
- signed, err := responderSignedOctets(initialResponse, initiatorNonce, suite, skpr, idr)
- if err != nil {
- t.Fatalf("responderSignedOctets() error = %v", err)
- }
- padded, _ := prf(suite, msk, []byte("Key Pad for IKEv2"))
- value, _ := prf(suite, padded, signed)
- auth := payload{Type: payloadAuth, Body: append([]byte{authMethodSharedKeyMIC, 0, 0, 0}, value...)}
- if err := verifyEAPResponderAUTH(auth, msk, initialResponse, initiatorNonce, suite, skpr, idr); err != nil {
- t.Fatalf("valid final responder AUTH rejected: %v", err)
- }
- auth.Body[len(auth.Body)-1] ^= 1
- if err := verifyEAPResponderAUTH(auth, msk, initialResponse, initiatorNonce, suite, skpr, idr); err == nil {
- t.Fatal("invalid final responder AUTH was accepted")
- }
- status, _, err := validateInitialResponderAUTH(
- []payload{idr},
- initialResponse,
- initiatorNonce,
- suite,
- skpr,
- "epdg.example",
- "epdg.example",
- nil,
- nil,
- false,
- )
- if status != vowifi.ResponderAUTHMissing || !errors.Is(err, vowifi.ErrResponderAUTHRequired) {
- t.Fatalf("strict missing initial AUTH = status %q err %v", status, err)
- }
- status, _, err = validateInitialResponderAUTH(
- []payload{idr},
- initialResponse,
- initiatorNonce,
- suite,
- skpr,
- "epdg.example",
- "epdg.example",
- nil,
- nil,
- true,
- )
- if status != vowifi.ResponderAUTHMissing || err != nil {
- t.Fatalf("EAP-only deferred initial AUTH = status %q err %v", status, err)
- }
- }
- func TestConfigurationIPv6PrefixIsMandatoryAndPreserved(t *testing.T) {
- ipv6 := bytes.Repeat([]byte{0x20}, 16)
- validBody := []byte{configReply, 0, 0, 0, 0, configInternalIPv6Address, 0, 17}
- validBody = append(validBody, ipv6...)
- validBody = append(validBody, 64)
- configuration, err := parseConfiguration(payload{Type: payloadCP, Body: validBody})
- if err != nil {
- t.Fatalf("parseConfiguration(valid IPv6) error = %v", err)
- }
- if configuration.IPv6Prefix != 64 || !bytes.Equal(configuration.LocalIPv6, ipv6) {
- t.Fatalf("IPv6 configuration = %#v", configuration)
- }
- invalidBody := []byte{configReply, 0, 0, 0, 0, configInternalIPv6Address, 0, 16}
- invalidBody = append(invalidBody, ipv6...)
- if _, err := parseConfiguration(payload{Type: payloadCP, Body: invalidBody}); err == nil {
- t.Fatal("16-byte INTERNAL_IP6_ADDRESS without prefix was accepted")
- }
- }
|