1package openpgp 2 3import ( 4 "bytes" 5 "crypto" 6 "strings" 7 "testing" 8 "time" 9 10 "golang.org/x/crypto/openpgp/errors" 11 "golang.org/x/crypto/openpgp/packet" 12) 13 14func TestKeyExpiry(t *testing.T) { 15 kring, err := ReadKeyRing(readerFromHex(expiringKeyHex)) 16 if err != nil { 17 t.Fatal(err) 18 } 19 entity := kring[0] 20 21 const timeFormat = "2006-01-02" 22 time1, _ := time.Parse(timeFormat, "2013-07-01") 23 24 // The expiringKeyHex key is structured as: 25 // 26 // pub 1024R/5E237D8C created: 2013-07-01 expires: 2013-07-31 usage: SC 27 // sub 1024R/1ABB25A0 created: 2013-07-01 23:11:07 +0200 CEST expires: 2013-07-08 usage: E 28 // sub 1024R/96A672F5 created: 2013-07-01 23:11:23 +0200 CEST expires: 2013-07-31 usage: E 29 // 30 // So this should select the newest, non-expired encryption key. 31 key, _ := entity.encryptionKey(time1) 32 if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected { 33 t.Errorf("Expected key %s at time %s, but got key %s", expected, time1.Format(timeFormat), id) 34 } 35 36 // Once the first encryption subkey has expired, the second should be 37 // selected. 38 time2, _ := time.Parse(timeFormat, "2013-07-09") 39 key, _ = entity.encryptionKey(time2) 40 if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected { 41 t.Errorf("Expected key %s at time %s, but got key %s", expected, time2.Format(timeFormat), id) 42 } 43 44 // Once all the keys have expired, nothing should be returned. 45 time3, _ := time.Parse(timeFormat, "2013-08-01") 46 if key, ok := entity.encryptionKey(time3); ok { 47 t.Errorf("Expected no key at time %s, but got key %s", time3.Format(timeFormat), key.PublicKey.KeyIdShortString()) 48 } 49} 50 51func TestMissingCrossSignature(t *testing.T) { 52 // This public key has a signing subkey, but the subkey does not 53 // contain a cross-signature. 54 keys, err := ReadArmoredKeyRing(bytes.NewBufferString(missingCrossSignatureKey)) 55 if len(keys) != 0 { 56 t.Errorf("Accepted key with missing cross signature") 57 } 58 if err == nil { 59 t.Fatal("Failed to detect error in keyring with missing cross signature") 60 } 61 structural, ok := err.(errors.StructuralError) 62 if !ok { 63 t.Fatalf("Unexpected class of error: %T. Wanted StructuralError", err) 64 } 65 const expectedMsg = "signing subkey is missing cross-signature" 66 if !strings.Contains(string(structural), expectedMsg) { 67 t.Fatalf("Unexpected error: %q. Expected it to contain %q", err, expectedMsg) 68 } 69} 70 71func TestInvalidCrossSignature(t *testing.T) { 72 // This public key has a signing subkey, and the subkey has an 73 // embedded cross-signature. However, the cross-signature does 74 // not correctly validate over the primary and subkey. 75 keys, err := ReadArmoredKeyRing(bytes.NewBufferString(invalidCrossSignatureKey)) 76 if len(keys) != 0 { 77 t.Errorf("Accepted key with invalid cross signature") 78 } 79 if err == nil { 80 t.Fatal("Failed to detect error in keyring with an invalid cross signature") 81 } 82 structural, ok := err.(errors.StructuralError) 83 if !ok { 84 t.Fatalf("Unexpected class of error: %T. Wanted StructuralError", err) 85 } 86 const expectedMsg = "subkey signature invalid" 87 if !strings.Contains(string(structural), expectedMsg) { 88 t.Fatalf("Unexpected error: %q. Expected it to contain %q", err, expectedMsg) 89 } 90} 91 92func TestGoodCrossSignature(t *testing.T) { 93 // This public key has a signing subkey, and the subkey has an 94 // embedded cross-signature which correctly validates over the 95 // primary and subkey. 96 keys, err := ReadArmoredKeyRing(bytes.NewBufferString(goodCrossSignatureKey)) 97 if err != nil { 98 t.Fatal(err) 99 } 100 if len(keys) != 1 { 101 t.Errorf("Failed to accept key with good cross signature, %d", len(keys)) 102 } 103 if len(keys[0].Subkeys) != 1 { 104 t.Errorf("Failed to accept good subkey, %d", len(keys[0].Subkeys)) 105 } 106} 107 108func TestRevokedUserID(t *testing.T) { 109 // This key contains 2 UIDs, one of which is revoked: 110 // [ultimate] (1) Golang Gopher <no-reply@golang.com> 111 // [ revoked] (2) Golang Gopher <revoked@golang.com> 112 keys, err := ReadArmoredKeyRing(bytes.NewBufferString(revokedUserIDKey)) 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 if len(keys) != 1 { 118 t.Fatal("Failed to read key with a revoked user id") 119 } 120 121 var identities []*Identity 122 for _, identity := range keys[0].Identities { 123 identities = append(identities, identity) 124 } 125 126 if numIdentities, numExpected := len(identities), 1; numIdentities != numExpected { 127 t.Errorf("obtained %d identities, expected %d", numIdentities, numExpected) 128 } 129 130 if identityName, expectedName := identities[0].Name, "Golang Gopher <no-reply@golang.com>"; identityName != expectedName { 131 t.Errorf("obtained identity %s expected %s", identityName, expectedName) 132 } 133} 134 135// TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission. 136func TestExternallyRevocableKey(t *testing.T) { 137 kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex)) 138 if err != nil { 139 t.Fatal(err) 140 } 141 142 // The 0xA42704B92866382A key can be revoked by 0xBE3893CB843D0FE70C 143 // according to this signature that appears within the key: 144 // :signature packet: algo 1, keyid A42704B92866382A 145 // version 4, created 1396409682, md5len 0, sigclass 0x1f 146 // digest algo 2, begin of digest a9 84 147 // hashed subpkt 2 len 4 (sig created 2014-04-02) 148 // hashed subpkt 12 len 22 (revocation key: c=80 a=1 f=CE094AA433F7040BB2DDF0BE3893CB843D0FE70C) 149 // hashed subpkt 7 len 1 (not revocable) 150 // subpkt 16 len 8 (issuer key ID A42704B92866382A) 151 // data: [1024 bits] 152 153 id := uint64(0xA42704B92866382A) 154 keys := kring.KeysById(id) 155 if len(keys) != 1 { 156 t.Errorf("Expected to find key id %X, but got %d matches", id, len(keys)) 157 } 158} 159 160func TestKeyRevocation(t *testing.T) { 161 kring, err := ReadKeyRing(readerFromHex(revokedKeyHex)) 162 if err != nil { 163 t.Fatal(err) 164 } 165 166 // revokedKeyHex contains these keys: 167 // pub 1024R/9A34F7C0 2014-03-25 [revoked: 2014-03-25] 168 // sub 1024R/1BA3CD60 2014-03-25 [revoked: 2014-03-25] 169 ids := []uint64{0xA401D9F09A34F7C0, 0x5CD3BE0A1BA3CD60} 170 171 for _, id := range ids { 172 keys := kring.KeysById(id) 173 if len(keys) != 1 { 174 t.Errorf("Expected KeysById to find revoked key %X, but got %d matches", id, len(keys)) 175 } 176 keys = kring.KeysByIdUsage(id, 0) 177 if len(keys) != 0 { 178 t.Errorf("Expected KeysByIdUsage to filter out revoked key %X, but got %d matches", id, len(keys)) 179 } 180 } 181} 182 183func TestKeyWithRevokedSubKey(t *testing.T) { 184 // This key contains a revoked sub key: 185 // pub rsa1024/0x4CBD826C39074E38 2018-06-14 [SC] 186 // Key fingerprint = 3F95 169F 3FFA 7D3F 2B47 6F0C 4CBD 826C 3907 4E38 187 // uid Golang Gopher <no-reply@golang.com> 188 // sub rsa1024/0x945DB1AF61D85727 2018-06-14 [S] [revoked: 2018-06-14] 189 190 keys, err := ReadArmoredKeyRing(bytes.NewBufferString(keyWithSubKey)) 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 if len(keys) != 1 { 196 t.Fatal("Failed to read key with a sub key") 197 } 198 199 identity := keys[0].Identities["Golang Gopher <no-reply@golang.com>"] 200 201 // Test for an issue where Subkey Binding Signatures (RFC 4880 5.2.1) were added to the identity 202 // preceding the Subkey Packet if the Subkey Packet was followed by more than one signature. 203 // For example, the current key has the following layout: 204 // PUBKEY UID SELFSIG SUBKEY REV SELFSIG 205 // The last SELFSIG would be added to the UID's signatures. This is wrong. 206 if numIdentitySigs, numExpected := len(identity.Signatures), 0; numIdentitySigs != numExpected { 207 t.Fatalf("got %d identity signatures, expected %d", numIdentitySigs, numExpected) 208 } 209 210 if numSubKeys, numExpected := len(keys[0].Subkeys), 1; numSubKeys != numExpected { 211 t.Fatalf("got %d subkeys, expected %d", numSubKeys, numExpected) 212 } 213 214 subKey := keys[0].Subkeys[0] 215 if subKey.Sig == nil { 216 t.Fatalf("subkey signature is nil") 217 } 218 219} 220 221func TestSubkeyRevocation(t *testing.T) { 222 kring, err := ReadKeyRing(readerFromHex(revokedSubkeyHex)) 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 // revokedSubkeyHex contains these keys: 228 // pub 1024R/4EF7E4BECCDE97F0 2014-03-25 229 // sub 1024R/D63636E2B96AE423 2014-03-25 230 // sub 1024D/DBCE4EE19529437F 2014-03-25 231 // sub 1024R/677815E371C2FD23 2014-03-25 [revoked: 2014-03-25] 232 validKeys := []uint64{0x4EF7E4BECCDE97F0, 0xD63636E2B96AE423, 0xDBCE4EE19529437F} 233 revokedKey := uint64(0x677815E371C2FD23) 234 235 for _, id := range validKeys { 236 keys := kring.KeysById(id) 237 if len(keys) != 1 { 238 t.Errorf("Expected KeysById to find key %X, but got %d matches", id, len(keys)) 239 } 240 keys = kring.KeysByIdUsage(id, 0) 241 if len(keys) != 1 { 242 t.Errorf("Expected KeysByIdUsage to find key %X, but got %d matches", id, len(keys)) 243 } 244 } 245 246 keys := kring.KeysById(revokedKey) 247 if len(keys) != 1 { 248 t.Errorf("Expected KeysById to find key %X, but got %d matches", revokedKey, len(keys)) 249 } 250 251 keys = kring.KeysByIdUsage(revokedKey, 0) 252 if len(keys) != 0 { 253 t.Errorf("Expected KeysByIdUsage to filter out revoked key %X, but got %d matches", revokedKey, len(keys)) 254 } 255} 256 257func TestKeyWithSubKeyAndBadSelfSigOrder(t *testing.T) { 258 // This key was altered so that the self signatures following the 259 // subkey are in a sub-optimal order. 260 // 261 // Note: Should someone have to create a similar key again, look into 262 // gpgsplit, gpg --dearmor, and gpg --enarmor. 263 // 264 // The packet ordering is the following: 265 // PUBKEY UID UIDSELFSIG SUBKEY SELFSIG1 SELFSIG2 266 // 267 // Where: 268 // SELFSIG1 expires on 2018-06-14 and was created first 269 // SELFSIG2 does not expire and was created after SELFSIG1 270 // 271 // Test for RFC 4880 5.2.3.3: 272 // > An implementation that encounters multiple self-signatures on the 273 // > same object may resolve the ambiguity in any way it sees fit, but it 274 // > is RECOMMENDED that priority be given to the most recent self- 275 // > signature. 276 // 277 // This means that we should keep SELFSIG2. 278 279 keys, err := ReadArmoredKeyRing(bytes.NewBufferString(keyWithSubKeyAndBadSelfSigOrder)) 280 if err != nil { 281 t.Fatal(err) 282 } 283 284 if len(keys) != 1 { 285 t.Fatal("Failed to read key with a sub key and a bad selfsig packet order") 286 } 287 288 key := keys[0] 289 290 if numKeys, expected := len(key.Subkeys), 1; numKeys != expected { 291 t.Fatalf("Read %d subkeys, expected %d", numKeys, expected) 292 } 293 294 subKey := key.Subkeys[0] 295 296 if lifetime := subKey.Sig.KeyLifetimeSecs; lifetime != nil { 297 t.Errorf("The signature has a key lifetime (%d), but it should be nil", *lifetime) 298 } 299 300} 301 302func TestKeyUsage(t *testing.T) { 303 kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex)) 304 if err != nil { 305 t.Fatal(err) 306 } 307 308 // subkeyUsageHex contains these keys: 309 // pub 1024R/2866382A created: 2014-04-01 expires: never usage: SC 310 // sub 1024R/936C9153 created: 2014-04-01 expires: never usage: E 311 // sub 1024R/64D5F5BB created: 2014-04-02 expires: never usage: E 312 // sub 1024D/BC0BA992 created: 2014-04-02 expires: never usage: S 313 certifiers := []uint64{0xA42704B92866382A} 314 signers := []uint64{0xA42704B92866382A, 0x42CE2C64BC0BA992} 315 encrypters := []uint64{0x09C0C7D9936C9153, 0xC104E98664D5F5BB} 316 317 for _, id := range certifiers { 318 keys := kring.KeysByIdUsage(id, packet.KeyFlagCertify) 319 if len(keys) == 1 { 320 if keys[0].PublicKey.KeyId != id { 321 t.Errorf("Expected to find certifier key id %X, but got %X", id, keys[0].PublicKey.KeyId) 322 } 323 } else { 324 t.Errorf("Expected one match for certifier key id %X, but got %d matches", id, len(keys)) 325 } 326 } 327 328 for _, id := range signers { 329 keys := kring.KeysByIdUsage(id, packet.KeyFlagSign) 330 if len(keys) == 1 { 331 if keys[0].PublicKey.KeyId != id { 332 t.Errorf("Expected to find signing key id %X, but got %X", id, keys[0].PublicKey.KeyId) 333 } 334 } else { 335 t.Errorf("Expected one match for signing key id %X, but got %d matches", id, len(keys)) 336 } 337 338 // This keyring contains no encryption keys that are also good for signing. 339 keys = kring.KeysByIdUsage(id, packet.KeyFlagEncryptStorage|packet.KeyFlagEncryptCommunications) 340 if len(keys) != 0 { 341 t.Errorf("Unexpected match for encryption key id %X", id) 342 } 343 } 344 345 for _, id := range encrypters { 346 keys := kring.KeysByIdUsage(id, packet.KeyFlagEncryptStorage|packet.KeyFlagEncryptCommunications) 347 if len(keys) == 1 { 348 if keys[0].PublicKey.KeyId != id { 349 t.Errorf("Expected to find encryption key id %X, but got %X", id, keys[0].PublicKey.KeyId) 350 } 351 } else { 352 t.Errorf("Expected one match for encryption key id %X, but got %d matches", id, len(keys)) 353 } 354 355 // This keyring contains no encryption keys that are also good for signing. 356 keys = kring.KeysByIdUsage(id, packet.KeyFlagSign) 357 if len(keys) != 0 { 358 t.Errorf("Unexpected match for signing key id %X", id) 359 } 360 } 361} 362 363func TestIdVerification(t *testing.T) { 364 kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex)) 365 if err != nil { 366 t.Fatal(err) 367 } 368 if err := kring[1].PrivateKey.Decrypt([]byte("passphrase")); err != nil { 369 t.Fatal(err) 370 } 371 372 const identity = "Test Key 1 (RSA)" 373 if err := kring[0].SignIdentity(identity, kring[1], nil); err != nil { 374 t.Fatal(err) 375 } 376 377 ident, ok := kring[0].Identities[identity] 378 if !ok { 379 t.Fatal("identity missing from key after signing") 380 } 381 382 checked := false 383 for _, sig := range ident.Signatures { 384 if sig.IssuerKeyId == nil || *sig.IssuerKeyId != kring[1].PrimaryKey.KeyId { 385 continue 386 } 387 388 if err := kring[1].PrimaryKey.VerifyUserIdSignature(identity, kring[0].PrimaryKey, sig); err != nil { 389 t.Fatalf("error verifying new identity signature: %s", err) 390 } 391 checked = true 392 break 393 } 394 395 if !checked { 396 t.Fatal("didn't find identity signature in Entity") 397 } 398} 399 400func TestNewEntityWithPreferredHash(t *testing.T) { 401 c := &packet.Config{ 402 DefaultHash: crypto.SHA256, 403 } 404 entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", c) 405 if err != nil { 406 t.Fatal(err) 407 } 408 409 for _, identity := range entity.Identities { 410 if len(identity.SelfSignature.PreferredHash) == 0 { 411 t.Fatal("didn't find a preferred hash in self signature") 412 } 413 ph := hashToHashId(c.DefaultHash) 414 if identity.SelfSignature.PreferredHash[0] != ph { 415 t.Fatalf("Expected preferred hash to be %d, got %d", ph, identity.SelfSignature.PreferredHash[0]) 416 } 417 } 418} 419 420func TestNewEntityWithoutPreferredHash(t *testing.T) { 421 entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil) 422 if err != nil { 423 t.Fatal(err) 424 } 425 426 for _, identity := range entity.Identities { 427 if len(identity.SelfSignature.PreferredHash) != 0 { 428 t.Fatalf("Expected preferred hash to be empty but got length %d", len(identity.SelfSignature.PreferredHash)) 429 } 430 } 431} 432 433func TestNewEntityCorrectName(t *testing.T) { 434 entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil) 435 if err != nil { 436 t.Fatal(err) 437 } 438 if len(entity.Identities) != 1 { 439 t.Fatalf("len(entity.Identities) = %d, want 1", len(entity.Identities)) 440 } 441 var got string 442 for _, i := range entity.Identities { 443 got = i.Name 444 } 445 want := "Golang Gopher (Test Key) <no-reply@golang.com>" 446 if got != want { 447 t.Fatalf("Identity.Name = %q, want %q", got, want) 448 } 449} 450 451func TestNewEntityWithPreferredSymmetric(t *testing.T) { 452 c := &packet.Config{ 453 DefaultCipher: packet.CipherAES256, 454 } 455 entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", c) 456 if err != nil { 457 t.Fatal(err) 458 } 459 460 for _, identity := range entity.Identities { 461 if len(identity.SelfSignature.PreferredSymmetric) == 0 { 462 t.Fatal("didn't find a preferred cipher in self signature") 463 } 464 if identity.SelfSignature.PreferredSymmetric[0] != uint8(c.DefaultCipher) { 465 t.Fatalf("Expected preferred cipher to be %d, got %d", uint8(c.DefaultCipher), identity.SelfSignature.PreferredSymmetric[0]) 466 } 467 } 468} 469 470func TestNewEntityWithoutPreferredSymmetric(t *testing.T) { 471 entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil) 472 if err != nil { 473 t.Fatal(err) 474 } 475 476 for _, identity := range entity.Identities { 477 if len(identity.SelfSignature.PreferredSymmetric) != 0 { 478 t.Fatalf("Expected preferred cipher to be empty but got length %d", len(identity.SelfSignature.PreferredSymmetric)) 479 } 480 } 481} 482 483func TestNewEntityPublicSerialization(t *testing.T) { 484 entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil) 485 if err != nil { 486 t.Fatal(err) 487 } 488 serializedEntity := bytes.NewBuffer(nil) 489 entity.Serialize(serializedEntity) 490 491 _, err = ReadEntity(packet.NewReader(bytes.NewBuffer(serializedEntity.Bytes()))) 492 if err != nil { 493 t.Fatal(err) 494 } 495} 496