summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/gtest/STSParserTest.cpp
blob: bedf57feab92f97888c4471071b04fddcf8ceea4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <stdio.h>

#include "gtest/gtest.h"
#include "nsNetUtil.h"
#include "nsISiteSecurityService.h"
#include "nsIURI.h"

void
TestSuccess(const char* hdr, bool extraTokens,
            uint64_t expectedMaxAge, bool expectedIncludeSubdomains,
            nsISiteSecurityService* sss)
{
  nsCOMPtr<nsIURI> dummyUri;
  nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
  ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to create URI";

  uint64_t maxAge = 0;
  bool includeSubdomains = false;
  rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
                                hdr, 0, &maxAge, &includeSubdomains, nullptr);
  ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to process valid header: " << hdr;

  ASSERT_EQ(maxAge, expectedMaxAge) << "Did not correctly parse maxAge";
  EXPECT_EQ(includeSubdomains, expectedIncludeSubdomains) <<
    "Did not correctly parse presence/absence of includeSubdomains";

  if (extraTokens) {
    EXPECT_EQ(rv, NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA) <<
      "Extra tokens were expected when parsing, but were not encountered.";
  } else {
    EXPECT_EQ(rv, NS_OK) << "Unexpected tokens found during parsing.";
  }

  printf("%s\n", hdr);
}

void TestFailure(const char* hdr,
                 nsISiteSecurityService* sss)
{
  nsCOMPtr<nsIURI> dummyUri;
  nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
  ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to create URI";

  rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
                                hdr, 0, nullptr, nullptr, nullptr);
  ASSERT_TRUE(NS_FAILED(rv)) << "Parsed invalid header: " << hdr;

  printf("%s\n", hdr);
}

TEST(psm_STSParser, Test)
{
    nsresult rv;

    // grab handle to the service
    nsCOMPtr<nsISiteSecurityService> sss;
    sss = do_GetService("@mozilla.org/ssservice;1", &rv);
    ASSERT_TRUE(NS_SUCCEEDED(rv));

    // *** parsing tests
    printf("*** Attempting to parse valid STS headers ...\n");

    // SHOULD SUCCEED:
    TestSuccess("max-age=100", false, 100, false, sss);
    TestSuccess("max-age  =100", false, 100, false, sss);
    TestSuccess(" max-age=100", false, 100, false, sss);
    TestSuccess("max-age = 100 ", false, 100, false, sss);
    TestSuccess("max-age = \"100\" ", false, 100, false, sss);
    TestSuccess("max-age=\"100\"", false, 100, false, sss);
    TestSuccess(" max-age =\"100\" ", false, 100, false, sss);
    TestSuccess("\tmax-age\t=\t\"100\"\t", false, 100, false, sss);
    TestSuccess("max-age  =       100             ", false, 100, false, sss);

    TestSuccess("maX-aGe=100", false, 100, false, sss);
    TestSuccess("MAX-age  =100", false, 100, false, sss);
    TestSuccess("max-AGE=100", false, 100, false, sss);
    TestSuccess("Max-Age = 100 ", false, 100, false, sss);
    TestSuccess("MAX-AGE = 100 ", false, 100, false, sss);

    TestSuccess("max-age=100;includeSubdomains", false, 100, true, sss);
    TestSuccess("max-age=100\t; includeSubdomains", false, 100, true, sss);
    TestSuccess(" max-age=100; includeSubdomains", false, 100, true, sss);
    TestSuccess("max-age = 100 ; includeSubdomains", false, 100, true, sss);
    TestSuccess("max-age  =       100             ; includeSubdomains",
                false, 100, true, sss);

    TestSuccess("maX-aGe=100; includeSUBDOMAINS", false, 100, true, sss);
    TestSuccess("MAX-age  =100; includeSubDomains", false, 100, true, sss);
    TestSuccess("max-AGE=100; iNcLuDeSuBdoMaInS", false, 100, true, sss);
    TestSuccess("Max-Age = 100; includesubdomains ", false, 100, true, sss);
    TestSuccess("INCLUDESUBDOMAINS;MaX-AgE = 100 ", false, 100, true, sss);
    // Turns out, the actual directive is entirely optional (hence the
    // trailing semicolon)
    TestSuccess("max-age=100;includeSubdomains;", true, 100, true, sss);

    // these are weird tests, but are testing that some extended syntax is
    // still allowed (but it is ignored)
    TestSuccess("max-age=100 ; includesubdomainsSomeStuff",
                true, 100, false, sss);
    TestSuccess("\r\n\t\t    \tcompletelyUnrelated = foobar; max-age= 34520103"
                "\t \t; alsoUnrelated;asIsThis;\tincludeSubdomains\t\t \t",
                true, 34520103, true, sss);
    TestSuccess("max-age=100; unrelated=\"quoted \\\"thingy\\\"\"",
                true, 100, false, sss);

    // SHOULD FAIL:
    printf("* Attempting to parse invalid STS headers (should not parse)...\n");
    // invalid max-ages
    TestFailure("max-age", sss);
    TestFailure("max-age ", sss);
    TestFailure("max-age=p", sss);
    TestFailure("max-age=*1p2", sss);
    TestFailure("max-age=.20032", sss);
    TestFailure("max-age=!20032", sss);
    TestFailure("max-age==20032", sss);

    // invalid headers
    TestFailure("foobar", sss);
    TestFailure("maxage=100", sss);
    TestFailure("maxa-ge=100", sss);
    TestFailure("max-ag=100", sss);
    TestFailure("includesubdomains", sss);
    TestFailure(";", sss);
    TestFailure("max-age=\"100", sss);
    // The max-age directive here doesn't conform to the spec, so it MUST
    // be ignored. Consequently, the REQUIRED max-age directive is not
    // present in this header, and so it is invalid.
    TestFailure("max-age=100, max-age=200; includeSubdomains", sss);
    TestFailure("max-age=100 includesubdomains", sss);
    TestFailure("max-age=100 bar foo", sss);
    TestFailure("max-age=100randomstuffhere", sss);
    // All directives MUST appear only once in an STS header field.
    TestFailure("max-age=100; max-age=200", sss);
    TestFailure("includeSubdomains; max-age=200; includeSubdomains", sss);
    TestFailure("max-age=200; includeSubdomains; includeSubdomains", sss);
    // The includeSubdomains directive is valueless.
    TestFailure("max-age=100; includeSubdomains=unexpected", sss);
    // LWS must have at least one space or horizontal tab
    TestFailure("\r\nmax-age=200", sss);
}