go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/network/resources/dnsshake/dkim_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package dnsshake 5 6 import ( 7 "errors" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 const ( 14 pubKey = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3E9IavfvGHiENM/bFBTJfRLBUE1PV9f2q2mbYOHu2d1zZ3VB22sXnpGN6TV1m8Tq8zUWlXPgkApOaSF/+zRqBuyF6ci1rmcfvFCAHdERXy37bFgi0/EkoslaqEZel4eddqqWt93KuwydPL2jEhd01M+PGbfFfCu65iZFW107u0PhlXWZG0iJbFsBNdp4mKXI4CxWNlVb0xPr0kcYaE0eAi+EcnG5QHONv5cQrQJ6ncUNehV0caUKWibIKTKPmwttPTyTYbF6sWY7olT9FAgbGz5flHHqBVWPXsf5Jivv5HbsJLTdejAvQwm7e+w0S//OFafffZUXgF/yNB4HczZiQIDAQAB` 15 ) 16 17 func TestDkimPublicKeyRepresentation(t *testing.T) { 18 type test struct { 19 Title string 20 DnsTxtRecord string 21 Expected *DkimPublicKeyRepresentation 22 ParseErr error 23 IsValid bool 24 } 25 26 // test cases for https://datatracker.ietf.org/doc/html/rfc6376#section-3.6.1 27 testCases := []test{ 28 { 29 Title: "minimal valid dkim", 30 DnsTxtRecord: "p=" + pubKey, 31 Expected: &DkimPublicKeyRepresentation{ 32 PublicKeyData: pubKey, 33 }, 34 IsValid: true, 35 }, 36 { 37 Title: "empty dkim record", 38 DnsTxtRecord: "", 39 Expected: &DkimPublicKeyRepresentation{}, 40 IsValid: false, 41 }, 42 // v= Version of the DKIM key record (plain-text; RECOMMENDED, default is "DKIM1") 43 { 44 Title: "v tag MUST be the first tag", 45 DnsTxtRecord: "p=" + pubKey + "; v=DKIM1", 46 Expected: nil, 47 ParseErr: errors.New("invalid DKIM record"), 48 IsValid: false, 49 }, 50 { 51 Title: "invalid DKIM version", 52 DnsTxtRecord: "v=DKIM1.0; p=" + pubKey, 53 Expected: &DkimPublicKeyRepresentation{ 54 Version: "DKIM1.0", 55 PublicKeyData: pubKey, 56 }, 57 IsValid: false, 58 }, 59 // h= Acceptable hash algorithms (plain-text; OPTIONAL, defaults to allowing all algorithms) 60 { 61 Title: "valid hash algorithms", 62 DnsTxtRecord: "v=DKIM1; h=sha1:sha256; p=" + pubKey, 63 Expected: &DkimPublicKeyRepresentation{ 64 Version: "DKIM1", 65 HashAlgorithms: []string{"sha1", "sha256"}, 66 PublicKeyData: pubKey, 67 }, 68 IsValid: true, 69 }, 70 { 71 Title: "single hash algorithm", 72 DnsTxtRecord: "v=DKIM1; h=sha256; p=" + pubKey, 73 Expected: &DkimPublicKeyRepresentation{ 74 Version: "DKIM1", 75 HashAlgorithms: []string{"sha256"}, 76 PublicKeyData: pubKey, 77 }, 78 IsValid: true, 79 }, 80 { 81 Title: "unsupported hash algorithm", 82 DnsTxtRecord: "v=DKIM1; h=sha512; p=" + pubKey, 83 Expected: &DkimPublicKeyRepresentation{ 84 Version: "DKIM1", 85 HashAlgorithms: []string{"sha512"}, 86 PublicKeyData: pubKey, 87 }, 88 IsValid: true, // still valid according to RFC: Unrecognized algorithms MUST be ignored 89 }, 90 { 91 Title: "empty hash list", 92 DnsTxtRecord: "v=DKIM1; h=; p=" + pubKey, 93 Expected: &DkimPublicKeyRepresentation{ 94 Version: "DKIM1", 95 HashAlgorithms: []string{""}, 96 PublicKeyData: pubKey, 97 }, 98 IsValid: true, // still valid according to RFC: defaults to allowing all algorithms 99 }, 100 // k= Key type (plain-text; OPTIONAL, default is "rsa") 101 { 102 Title: "valid DKIM with rsa key type and public key", 103 DnsTxtRecord: "v=DKIM1; k=rsa; p=" + pubKey, 104 Expected: &DkimPublicKeyRepresentation{ 105 Version: "DKIM1", 106 KeyType: "rsa", 107 PublicKeyData: pubKey, 108 }, 109 IsValid: true, 110 }, 111 { 112 Title: "unsupported public key type", 113 DnsTxtRecord: "v=DKIM1; k=dsa; p=" + pubKey, 114 Expected: &DkimPublicKeyRepresentation{ 115 Version: "DKIM1", 116 KeyType: "dsa", 117 PublicKeyData: pubKey, 118 }, 119 IsValid: false, 120 }, 121 { 122 Title: "empty_key_type", 123 DnsTxtRecord: "v=DKIM1; k=; p=" + pubKey, 124 Expected: &DkimPublicKeyRepresentation{ 125 Version: "DKIM1", 126 PublicKeyData: pubKey, 127 }, 128 IsValid: true, // valid since it defaults to rsa 129 }, 130 // n= Notes that might be of interest to a human 131 { 132 Title: "empty note", 133 DnsTxtRecord: "v=DKIM1; n=; p=" + pubKey, 134 Expected: &DkimPublicKeyRepresentation{ 135 Version: "DKIM1", 136 PublicKeyData: pubKey, 137 }, 138 IsValid: true, 139 }, 140 { 141 Title: "with simple note", 142 DnsTxtRecord: "v=DKIM1; n=a note; p=" + pubKey, 143 Expected: &DkimPublicKeyRepresentation{ 144 Version: "DKIM1", 145 Notes: "a note", 146 PublicKeyData: pubKey, 147 }, 148 IsValid: true, 149 }, 150 { 151 // see https://en.wikipedia.org/wiki/Quoted-printable 152 Title: "quoted printable note", 153 DnsTxtRecord: "v=DKIM1; n=H=E4tten H=FCte ein =DF im Namen, w=E4ren sie m=F6glicherweise keine H=FCte= mehr,sondern H=FC=DFe.; p=" + pubKey, 154 Expected: &DkimPublicKeyRepresentation{ 155 Version: "DKIM1", 156 Notes: "H\xe4tten H\xfcte ein \xdf im Namen, w\xe4ren sie m\xf6glicherweise keine H\xfcte= mehr,sondern H\xfc\xdfe.", 157 PublicKeyData: pubKey, 158 }, 159 IsValid: true, 160 }, 161 { 162 Title: "uninterpreted note", 163 DnsTxtRecord: "v=DKIM1; n=Hätten; p=" + pubKey, 164 Expected: &DkimPublicKeyRepresentation{ 165 Version: "DKIM1", 166 Notes: "Hätten", 167 PublicKeyData: pubKey, 168 }, 169 IsValid: true, 170 }, 171 // p= Public-key data (base64; REQUIRED) 172 { 173 Title: "missing public key", 174 DnsTxtRecord: "v=DKIM1", 175 Expected: &DkimPublicKeyRepresentation{ 176 Version: "DKIM1", 177 }, 178 IsValid: false, 179 }, 180 { 181 Title: "revoked public key", 182 DnsTxtRecord: "v=DKIM1; p=", 183 Expected: &DkimPublicKeyRepresentation{ 184 Version: "DKIM1", 185 }, 186 IsValid: false, 187 }, 188 { 189 Title: "invalid base64 public key", 190 DnsTxtRecord: "v=DKIM1; p=invalidBase64key", 191 Expected: &DkimPublicKeyRepresentation{ 192 Version: "DKIM1", 193 PublicKeyData: "invalidBase64key", 194 }, 195 IsValid: false, 196 }, 197 // s= Service Type (plain-text; OPTIONAL; default is "*") 198 { 199 Title: "matches all service types", 200 DnsTxtRecord: "v=DKIM1; s=*; p=" + pubKey, 201 Expected: &DkimPublicKeyRepresentation{ 202 Version: "DKIM1", 203 ServiceType: []string{"*"}, 204 PublicKeyData: pubKey, 205 }, 206 IsValid: true, 207 }, 208 { 209 Title: "email service type", 210 DnsTxtRecord: "v=DKIM1; s=email; p=" + pubKey, 211 Expected: &DkimPublicKeyRepresentation{ 212 Version: "DKIM1", 213 ServiceType: []string{"email"}, 214 PublicKeyData: pubKey, 215 }, 216 IsValid: true, 217 }, 218 { 219 Title: "unsupported service type", 220 DnsTxtRecord: "v=DKIM1; s=unsupported; p=" + pubKey, 221 Expected: &DkimPublicKeyRepresentation{ 222 Version: "DKIM1", 223 ServiceType: []string{"unsupported"}, 224 PublicKeyData: pubKey, 225 }, 226 IsValid: true, 227 }, 228 { 229 Title: "colon separated service type list with supported and unsupported entries", 230 DnsTxtRecord: "v=DKIM1; s=email:unsupported; p=" + pubKey, 231 Expected: &DkimPublicKeyRepresentation{ 232 Version: "DKIM1", 233 ServiceType: []string{"email", "unsupported"}, 234 PublicKeyData: pubKey, 235 }, 236 IsValid: true, 237 }, 238 { 239 Title: "empty services types", 240 DnsTxtRecord: "v=DKIM1; s=; p=" + pubKey, 241 Expected: &DkimPublicKeyRepresentation{ 242 Version: "DKIM1", 243 ServiceType: []string{""}, 244 PublicKeyData: pubKey, 245 }, 246 IsValid: true, 247 }, 248 249 // t= Flags, represented as a colon-separated list of name 250 { 251 Title: "testing mode flag", 252 DnsTxtRecord: "v=DKIM1; t=y; p=" + pubKey, 253 Expected: &DkimPublicKeyRepresentation{ 254 Version: "DKIM1", 255 PublicKeyData: pubKey, 256 Flags: []string{"y"}, 257 }, 258 IsValid: true, 259 }, 260 { 261 Title: "include invalid test flag", 262 DnsTxtRecord: "v=DKIM1; t=y:s:?; p=" + pubKey, 263 Expected: &DkimPublicKeyRepresentation{ 264 Version: "DKIM1", 265 HashAlgorithms: nil, 266 KeyType: "", 267 ServiceType: nil, 268 PublicKeyData: pubKey, 269 Flags: []string{"y", "s", "?"}, 270 }, 271 IsValid: true, 272 }, 273 { 274 Title: "no flags", 275 DnsTxtRecord: "v=DKIM1; t=; p=" + pubKey, 276 Expected: &DkimPublicKeyRepresentation{ 277 Version: "DKIM1", 278 PublicKeyData: pubKey, 279 Flags: []string{""}, 280 }, 281 IsValid: true, 282 }, 283 } 284 285 for i := range testCases { 286 tc := testCases[i] 287 t.Run(tc.Title, func(t *testing.T) { 288 // parse dns entry 289 pubKeyRep, err := NewDkimPublicKeyRepresentation(tc.DnsTxtRecord) 290 if tc.ParseErr != nil { 291 assert.EqualError(t, err, tc.ParseErr.Error()) 292 } else { 293 assert.NoError(t, err) 294 } 295 296 // check that the data was parsed as expected 297 assert.EqualValues(t, tc.Expected, pubKeyRep) 298 299 // check if validation is successful 300 if pubKeyRep != nil { 301 valid, _, _ := pubKeyRep.Valid() 302 assert.Equal(t, tc.IsValid, valid) 303 } 304 }) 305 } 306 }