Merge branch 'master' into send_error_use_error
This commit is contained in:
commit
1b9e858681
|
|
@ -110,7 +110,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/letsencrypt/go-jose",
|
||||
"Rev": "77671e91fe89678878df4bde9e6b653a0d190dfb"
|
||||
"Rev": "15b73d6f0363b256ddb080db1c64563064a4e773"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/letsencrypt/go-safe-browsing-api",
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/dns",
|
||||
"Rev": "7ff8d29c8b70b10f383a11f03b7bf5b7408bf41a"
|
||||
"Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/pkcs11",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ go:
|
|||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- tip
|
||||
|
||||
before_script:
|
||||
|
|
|
|||
431
Godeps/_workspace/src/github.com/letsencrypt/go-jose/asymmetric_test.go
generated
vendored
Normal file
431
Godeps/_workspace/src/github.com/letsencrypt/go-jose/asymmetric_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVectorsRSA(t *testing.T) {
|
||||
// Sources:
|
||||
// http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-rsa-cryptography-standard.htm
|
||||
// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
|
||||
priv := &rsa.PrivateKey{
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: fromHexInt(`
|
||||
a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8
|
||||
ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0c
|
||||
bc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bd
|
||||
bf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93
|
||||
ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb`),
|
||||
E: 65537,
|
||||
},
|
||||
D: fromHexInt(`
|
||||
53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf1195
|
||||
17ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d
|
||||
4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d6
|
||||
5a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb
|
||||
04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1`),
|
||||
Primes: []*big.Int{
|
||||
fromHexInt(`
|
||||
d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262
|
||||
864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c
|
||||
2f26a471dcad212eac7ca39d`),
|
||||
fromHexInt(`
|
||||
cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb3
|
||||
3d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af
|
||||
72bfe9a030e860b0288b5d77`),
|
||||
},
|
||||
}
|
||||
|
||||
input := fromHexBytes(
|
||||
"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34")
|
||||
|
||||
expectedPKCS := fromHexBytes(`
|
||||
50b4c14136bd198c2f3c3ed243fce036e168d56517984a263cd66492b808
|
||||
04f169d210f2b9bdfb48b12f9ea05009c77da257cc600ccefe3a6283789d
|
||||
8ea0e607ac58e2690ec4ebc10146e8cbaa5ed4d5cce6fe7b0ff9efc1eabb
|
||||
564dbf498285f449ee61dd7b42ee5b5892cb90601f30cda07bf26489310b
|
||||
cd23b528ceab3c31`)
|
||||
|
||||
expectedOAEP := fromHexBytes(`
|
||||
354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad4
|
||||
68fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618
|
||||
c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e6
|
||||
57a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5
|
||||
210035d47ac72e8a`)
|
||||
|
||||
// Mock random reader
|
||||
randReader = bytes.NewReader(fromHexBytes(`
|
||||
017341ae3875d5f87101f8cc4fa9b9bc156bb04628fccdb2f4f11e905bd3
|
||||
a155d376f593bd7304210874eba08a5e22bcccb4c9d3882a93a54db022f5
|
||||
03d16338b6b7ce16dc7f4bbf9a96b59772d6606e9747c7649bf9e083db98
|
||||
1884a954ab3c6f18b776ea21069d69776a33e96bad48e1dda0a5ef`))
|
||||
defer resetRandReader()
|
||||
|
||||
// RSA-PKCS1v1.5 encrypt
|
||||
enc := new(rsaEncrypterVerifier)
|
||||
enc.publicKey = &priv.PublicKey
|
||||
encryptedPKCS, err := enc.encrypt(input, RSA1_5)
|
||||
if err != nil {
|
||||
t.Error("Encryption failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(encryptedPKCS, expectedPKCS) != 0 {
|
||||
t.Error("Output does not match expected value (PKCS1v1.5)")
|
||||
}
|
||||
|
||||
// RSA-OAEP encrypt
|
||||
encryptedOAEP, err := enc.encrypt(input, RSA_OAEP)
|
||||
if err != nil {
|
||||
t.Error("Encryption failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(encryptedOAEP, expectedOAEP) != 0 {
|
||||
t.Error("Output does not match expected value (OAEP)")
|
||||
}
|
||||
|
||||
// Need fake cipher for PKCS1v1.5 decrypt
|
||||
resetRandReader()
|
||||
aes := newAESGCM(len(input))
|
||||
|
||||
keygen := randomKeyGenerator{
|
||||
size: aes.keySize(),
|
||||
}
|
||||
|
||||
// RSA-PKCS1v1.5 decrypt
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = priv
|
||||
decryptedPKCS, err := dec.decrypt(encryptedPKCS, RSA1_5, keygen)
|
||||
if err != nil {
|
||||
t.Error("Decryption failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(input, decryptedPKCS) != 0 {
|
||||
t.Error("Output does not match expected value (PKCS1v1.5)")
|
||||
}
|
||||
|
||||
// RSA-OAEP decrypt
|
||||
decryptedOAEP, err := dec.decrypt(encryptedOAEP, RSA_OAEP, keygen)
|
||||
if err != nil {
|
||||
t.Error("decryption failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(input, decryptedOAEP) != 0 {
|
||||
t.Error("output does not match expected value (OAEP)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidAlgorithmsRSA(t *testing.T) {
|
||||
_, err := newRSARecipient("XYZ", nil)
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
_, err = newRSASigner("XYZ", nil)
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
enc := new(rsaEncrypterVerifier)
|
||||
enc.publicKey = &rsaTestKey.PublicKey
|
||||
_, err = enc.encryptKey([]byte{}, "XYZ")
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
err = enc.verifyPayload([]byte{}, []byte{}, "XYZ")
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = rsaTestKey
|
||||
_, err = dec.decrypt(make([]byte, 256), "XYZ", randomKeyGenerator{size: 16})
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
_, err = dec.signPayload([]byte{}, "XYZ")
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
type failingKeyGenerator struct{}
|
||||
|
||||
func (ctx failingKeyGenerator) keySize() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (ctx failingKeyGenerator) genKey() ([]byte, rawHeader, error) {
|
||||
return nil, rawHeader{}, errors.New("failed to generate key")
|
||||
}
|
||||
|
||||
func TestPKCSKeyGeneratorFailure(t *testing.T) {
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = rsaTestKey
|
||||
generator := failingKeyGenerator{}
|
||||
_, err := dec.decrypt(make([]byte, 256), RSA1_5, generator)
|
||||
if err != ErrCryptoFailure {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidAlgorithmsEC(t *testing.T) {
|
||||
_, err := newECDHRecipient("XYZ", nil)
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
_, err = newECDSASigner("XYZ", nil)
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
|
||||
enc := new(ecEncrypterVerifier)
|
||||
enc.publicKey = &ecTestKey256.PublicKey
|
||||
_, err = enc.encryptKey([]byte{}, "XYZ")
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should return error on invalid algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidECKeyGen(t *testing.T) {
|
||||
gen := ecKeyGenerator{
|
||||
size: 16,
|
||||
algID: "A128GCM",
|
||||
publicKey: &ecTestKey256.PublicKey,
|
||||
}
|
||||
|
||||
if gen.keySize() != 16 {
|
||||
t.Error("ec key generator reported incorrect key size")
|
||||
}
|
||||
|
||||
_, _, err := gen.genKey()
|
||||
if err != nil {
|
||||
t.Error("ec key generator failed to generate key", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidECDecrypt(t *testing.T) {
|
||||
dec := ecDecrypterSigner{
|
||||
privateKey: ecTestKey256,
|
||||
}
|
||||
|
||||
generator := randomKeyGenerator{size: 16}
|
||||
|
||||
// Missing epk header
|
||||
headers := rawHeader{
|
||||
Alg: string(ECDH_ES),
|
||||
}
|
||||
|
||||
_, err := dec.decryptKey(headers, nil, generator)
|
||||
if err == nil {
|
||||
t.Error("ec decrypter accepted object with missing epk header")
|
||||
}
|
||||
|
||||
// Invalid epk header
|
||||
headers.Epk = &JsonWebKey{}
|
||||
|
||||
_, err = dec.decryptKey(headers, nil, generator)
|
||||
if err == nil {
|
||||
t.Error("ec decrypter accepted object with invalid epk header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecryptWithIncorrectSize(t *testing.T) {
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = priv
|
||||
aes := newAESGCM(16)
|
||||
|
||||
keygen := randomKeyGenerator{
|
||||
size: aes.keySize(),
|
||||
}
|
||||
|
||||
payload := make([]byte, 254)
|
||||
_, err = dec.decrypt(payload, RSA1_5, keygen)
|
||||
if err == nil {
|
||||
t.Error("Invalid payload size should return error")
|
||||
}
|
||||
|
||||
payload = make([]byte, 257)
|
||||
_, err = dec.decrypt(payload, RSA1_5, keygen)
|
||||
if err == nil {
|
||||
t.Error("Invalid payload size should return error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCSDecryptNeverFails(t *testing.T) {
|
||||
// We don't want RSA-PKCS1 v1.5 decryption to ever fail, in order to prevent
|
||||
// side-channel timing attacks (Bleichenbacher attack in particular).
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = priv
|
||||
aes := newAESGCM(16)
|
||||
|
||||
keygen := randomKeyGenerator{
|
||||
size: aes.keySize(),
|
||||
}
|
||||
|
||||
for i := 1; i < 50; i++ {
|
||||
payload := make([]byte, 256)
|
||||
_, err := io.ReadFull(rand.Reader, payload)
|
||||
if err != nil {
|
||||
t.Error("Unable to get random data:", err)
|
||||
return
|
||||
}
|
||||
_, err = dec.decrypt(payload, RSA1_5, keygen)
|
||||
if err != nil {
|
||||
t.Error("PKCS1v1.5 decrypt should never fail:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPKCSDecryptWithValidPayloads(b *testing.B) {
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enc := new(rsaEncrypterVerifier)
|
||||
enc.publicKey = &priv.PublicKey
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = priv
|
||||
aes := newAESGCM(32)
|
||||
|
||||
b.StopTimer()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
plaintext := make([]byte, 32)
|
||||
_, err = io.ReadFull(rand.Reader, plaintext)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ciphertext, err := enc.encrypt(plaintext, RSA1_5)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
keygen := randomKeyGenerator{
|
||||
size: aes.keySize(),
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
_, err = dec.decrypt(ciphertext, RSA1_5, keygen)
|
||||
b.StopTimer()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPKCSDecryptWithInvalidPayloads(b *testing.B) {
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enc := new(rsaEncrypterVerifier)
|
||||
enc.publicKey = &priv.PublicKey
|
||||
dec := new(rsaDecrypterSigner)
|
||||
dec.privateKey = priv
|
||||
aes := newAESGCM(16)
|
||||
|
||||
keygen := randomKeyGenerator{
|
||||
size: aes.keySize(),
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
plaintext := make([]byte, 16)
|
||||
_, err = io.ReadFull(rand.Reader, plaintext)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ciphertext, err := enc.encrypt(plaintext, RSA1_5)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Do some simple scrambling
|
||||
ciphertext[128] ^= 0xFF
|
||||
|
||||
b.StartTimer()
|
||||
_, err = dec.decrypt(ciphertext, RSA1_5, keygen)
|
||||
b.StopTimer()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidEllipticCurve(t *testing.T) {
|
||||
signer256 := ecDecrypterSigner{privateKey: ecTestKey256}
|
||||
signer384 := ecDecrypterSigner{privateKey: ecTestKey384}
|
||||
signer521 := ecDecrypterSigner{privateKey: ecTestKey521}
|
||||
|
||||
_, err := signer256.signPayload([]byte{}, ES384)
|
||||
if err == nil {
|
||||
t.Error("should not generate ES384 signature with P-256 key")
|
||||
}
|
||||
_, err = signer256.signPayload([]byte{}, ES512)
|
||||
if err == nil {
|
||||
t.Error("should not generate ES512 signature with P-256 key")
|
||||
}
|
||||
_, err = signer384.signPayload([]byte{}, ES256)
|
||||
if err == nil {
|
||||
t.Error("should not generate ES256 signature with P-384 key")
|
||||
}
|
||||
_, err = signer384.signPayload([]byte{}, ES512)
|
||||
if err == nil {
|
||||
t.Error("should not generate ES512 signature with P-384 key")
|
||||
}
|
||||
_, err = signer521.signPayload([]byte{}, ES256)
|
||||
if err == nil {
|
||||
t.Error("should not generate ES256 signature with P-521 key")
|
||||
}
|
||||
_, err = signer521.signPayload([]byte{}, ES384)
|
||||
if err == nil {
|
||||
t.Error("should not generate ES384 signature with P-521 key")
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,14 @@ func (ctx *cbcAEAD) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
cbc := cipher.NewCBCDecrypter(ctx.blockCipher, nonce)
|
||||
buffer := []byte(ciphertext[:offset])
|
||||
|
||||
// Make copy of ciphertext buffer, don't want to modify in place
|
||||
buffer := append([]byte{}, []byte(ciphertext[:offset])...)
|
||||
|
||||
if len(buffer)%ctx.blockCipher.BlockSize() > 0 {
|
||||
return nil, errors.New("square/go-jose: invalid ciphertext (invalid length)")
|
||||
}
|
||||
|
||||
cbc.CryptBlocks(buffer, buffer)
|
||||
|
||||
// Remove padding
|
||||
|
|
@ -176,7 +183,7 @@ func unpadBuffer(buffer []byte, blockSize int) ([]byte, error) {
|
|||
last := buffer[len(buffer)-1]
|
||||
count := int(last)
|
||||
|
||||
if count > blockSize || count > len(buffer) {
|
||||
if count == 0 || count > blockSize || count > len(buffer) {
|
||||
return nil, errors.New("square/go-jose: invalid padding")
|
||||
}
|
||||
|
||||
|
|
|
|||
498
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/cbc_hmac_test.go
generated
vendored
Normal file
498
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/cbc_hmac_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package josecipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInvalidInputs(t *testing.T) {
|
||||
key := []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
}
|
||||
|
||||
nonce := []byte{
|
||||
92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
|
||||
|
||||
aead, _ := NewCBCHMAC(key, aes.NewCipher)
|
||||
ciphertext := aead.Seal(nil, nonce, []byte("plaintext"), []byte("aad"))
|
||||
|
||||
// Changed AAD, must fail
|
||||
_, err := aead.Open(nil, nonce, ciphertext, []byte("INVALID"))
|
||||
if err == nil {
|
||||
t.Error("must detect invalid aad")
|
||||
}
|
||||
|
||||
// Empty ciphertext, must fail
|
||||
_, err = aead.Open(nil, nonce, []byte{}, []byte("aad"))
|
||||
if err == nil {
|
||||
t.Error("must detect invalid/empty ciphertext")
|
||||
}
|
||||
|
||||
// Corrupt ciphertext, must fail
|
||||
corrupt := make([]byte, len(ciphertext))
|
||||
copy(corrupt, ciphertext)
|
||||
corrupt[0] ^= 0xFF
|
||||
|
||||
_, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
|
||||
if err == nil {
|
||||
t.Error("must detect corrupt ciphertext")
|
||||
}
|
||||
|
||||
// Corrupt authtag, must fail
|
||||
copy(corrupt, ciphertext)
|
||||
corrupt[len(ciphertext)-1] ^= 0xFF
|
||||
|
||||
_, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
|
||||
if err == nil {
|
||||
t.Error("must detect corrupt authtag")
|
||||
}
|
||||
|
||||
// Truncated data, must fail
|
||||
_, err = aead.Open(nil, nonce, ciphertext[:10], []byte("aad"))
|
||||
if err == nil {
|
||||
t.Error("must detect corrupt authtag")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVectorsAESCBC128(t *testing.T) {
|
||||
// Source: http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-29#appendix-A.2
|
||||
plaintext := []byte{
|
||||
76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
|
||||
112, 114, 111, 115, 112, 101, 114, 46}
|
||||
|
||||
aad := []byte{
|
||||
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
|
||||
120, 88, 122, 85, 105, 76, 67, 74, 108, 98, 109, 77, 105, 79, 105,
|
||||
74, 66, 77, 84, 73, 52, 81, 48, 74, 68, 76, 85, 104, 84, 77, 106, 85,
|
||||
50, 73, 110, 48}
|
||||
|
||||
expectedCiphertext := []byte{
|
||||
40, 57, 83, 181, 119, 33, 133, 148, 198, 185, 243, 24, 152, 230, 6,
|
||||
75, 129, 223, 127, 19, 210, 82, 183, 230, 168, 33, 215, 104, 143,
|
||||
112, 56, 102}
|
||||
|
||||
expectedAuthtag := []byte{
|
||||
246, 17, 244, 190, 4, 95, 98, 3, 231, 0, 115, 157, 242, 203, 100,
|
||||
191}
|
||||
|
||||
key := []byte{
|
||||
4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106, 206,
|
||||
107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, 44, 207}
|
||||
|
||||
nonce := []byte{
|
||||
3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101}
|
||||
|
||||
enc, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
out := enc.Seal(nil, nonce, plaintext, aad)
|
||||
if err != nil {
|
||||
t.Error("Unable to encrypt:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(out[:len(out)-16], expectedCiphertext) != 0 {
|
||||
t.Error("Ciphertext did not match")
|
||||
}
|
||||
if bytes.Compare(out[len(out)-16:], expectedAuthtag) != 0 {
|
||||
t.Error("Auth tag did not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVectorsAESCBC256(t *testing.T) {
|
||||
// Source: https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05#section-5.4
|
||||
plaintext := []byte{
|
||||
0x41, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
|
||||
0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75,
|
||||
0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65,
|
||||
0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
|
||||
0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x20, 0x69,
|
||||
0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x66,
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x65, 0x6d, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f,
|
||||
0x75, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65}
|
||||
|
||||
aad := []byte{
|
||||
0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x65, 0x20,
|
||||
0x4b, 0x65, 0x72, 0x63, 0x6b, 0x68, 0x6f, 0x66, 0x66, 0x73}
|
||||
|
||||
expectedCiphertext := []byte{
|
||||
0x4a, 0xff, 0xaa, 0xad, 0xb7, 0x8c, 0x31, 0xc5, 0xda, 0x4b, 0x1b, 0x59, 0x0d, 0x10, 0xff, 0xbd,
|
||||
0x3d, 0xd8, 0xd5, 0xd3, 0x02, 0x42, 0x35, 0x26, 0x91, 0x2d, 0xa0, 0x37, 0xec, 0xbc, 0xc7, 0xbd,
|
||||
0x82, 0x2c, 0x30, 0x1d, 0xd6, 0x7c, 0x37, 0x3b, 0xcc, 0xb5, 0x84, 0xad, 0x3e, 0x92, 0x79, 0xc2,
|
||||
0xe6, 0xd1, 0x2a, 0x13, 0x74, 0xb7, 0x7f, 0x07, 0x75, 0x53, 0xdf, 0x82, 0x94, 0x10, 0x44, 0x6b,
|
||||
0x36, 0xeb, 0xd9, 0x70, 0x66, 0x29, 0x6a, 0xe6, 0x42, 0x7e, 0xa7, 0x5c, 0x2e, 0x08, 0x46, 0xa1,
|
||||
0x1a, 0x09, 0xcc, 0xf5, 0x37, 0x0d, 0xc8, 0x0b, 0xfe, 0xcb, 0xad, 0x28, 0xc7, 0x3f, 0x09, 0xb3,
|
||||
0xa3, 0xb7, 0x5e, 0x66, 0x2a, 0x25, 0x94, 0x41, 0x0a, 0xe4, 0x96, 0xb2, 0xe2, 0xe6, 0x60, 0x9e,
|
||||
0x31, 0xe6, 0xe0, 0x2c, 0xc8, 0x37, 0xf0, 0x53, 0xd2, 0x1f, 0x37, 0xff, 0x4f, 0x51, 0x95, 0x0b,
|
||||
0xbe, 0x26, 0x38, 0xd0, 0x9d, 0xd7, 0xa4, 0x93, 0x09, 0x30, 0x80, 0x6d, 0x07, 0x03, 0xb1, 0xf6}
|
||||
|
||||
expectedAuthtag := []byte{
|
||||
0x4d, 0xd3, 0xb4, 0xc0, 0x88, 0xa7, 0xf4, 0x5c, 0x21, 0x68, 0x39, 0x64, 0x5b, 0x20, 0x12, 0xbf,
|
||||
0x2e, 0x62, 0x69, 0xa8, 0xc5, 0x6a, 0x81, 0x6d, 0xbc, 0x1b, 0x26, 0x77, 0x61, 0x95, 0x5b, 0xc5}
|
||||
|
||||
key := []byte{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}
|
||||
|
||||
nonce := []byte{
|
||||
0x1a, 0xf3, 0x8c, 0x2d, 0xc2, 0xb9, 0x6f, 0xfd, 0xd8, 0x66, 0x94, 0x09, 0x23, 0x41, 0xbc, 0x04}
|
||||
|
||||
enc, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
out := enc.Seal(nil, nonce, plaintext, aad)
|
||||
if err != nil {
|
||||
t.Error("Unable to encrypt:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(out[:len(out)-32], expectedCiphertext) != 0 {
|
||||
t.Error("Ciphertext did not match, got", out[:len(out)-32], "wanted", expectedCiphertext)
|
||||
}
|
||||
if bytes.Compare(out[len(out)-32:], expectedAuthtag) != 0 {
|
||||
t.Error("Auth tag did not match, got", out[len(out)-32:], "wanted", expectedAuthtag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAESCBCRoundtrip(t *testing.T) {
|
||||
key128 := []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||
|
||||
key192 := []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7}
|
||||
|
||||
key256 := []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||
|
||||
nonce := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||
|
||||
RunRoundtrip(t, key128, nonce)
|
||||
RunRoundtrip(t, key192, nonce)
|
||||
RunRoundtrip(t, key256, nonce)
|
||||
}
|
||||
|
||||
func RunRoundtrip(t *testing.T, key, nonce []byte) {
|
||||
aead, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if aead.NonceSize() != len(nonce) {
|
||||
panic("invalid nonce")
|
||||
}
|
||||
|
||||
// Test pre-existing data in dst buffer
|
||||
dst := []byte{15, 15, 15, 15}
|
||||
plaintext := []byte{0, 0, 0, 0}
|
||||
aad := []byte{4, 3, 2, 1}
|
||||
|
||||
result := aead.Seal(dst, nonce, plaintext, aad)
|
||||
if bytes.Compare(dst, result[:4]) != 0 {
|
||||
t.Error("Existing data in dst not preserved")
|
||||
}
|
||||
|
||||
// Test pre-existing (empty) dst buffer with sufficient capacity
|
||||
dst = make([]byte, 256)[:0]
|
||||
result, err = aead.Open(dst, nonce, result[4:], aad)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if bytes.Compare(result, plaintext) != 0 {
|
||||
t.Error("Plaintext does not match output")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAESCBCOverhead(t *testing.T) {
|
||||
aead, err := NewCBCHMAC(make([]byte, 32), aes.NewCipher)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if aead.Overhead() != 32 {
|
||||
t.Error("CBC-HMAC reports incorrect overhead value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPadding(t *testing.T) {
|
||||
for i := 0; i < 256; i++ {
|
||||
slice := make([]byte, i)
|
||||
padded := padBuffer(slice, 16)
|
||||
if len(padded)%16 != 0 {
|
||||
t.Error("failed to pad slice properly", i)
|
||||
return
|
||||
}
|
||||
unpadded, err := unpadBuffer(padded, 16)
|
||||
if err != nil || len(unpadded) != i {
|
||||
t.Error("failed to unpad slice properly", i)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidKey(t *testing.T) {
|
||||
key := make([]byte, 30)
|
||||
_, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
if err == nil {
|
||||
t.Error("should not be able to instantiate CBC-HMAC with invalid key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncatedCiphertext(t *testing.T) {
|
||||
key := make([]byte, 32)
|
||||
nonce := make([]byte, 16)
|
||||
data := make([]byte, 32)
|
||||
|
||||
io.ReadFull(rand.Reader, key)
|
||||
io.ReadFull(rand.Reader, nonce)
|
||||
|
||||
aead, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctx := aead.(*cbcAEAD)
|
||||
ct := aead.Seal(nil, nonce, data, nil)
|
||||
|
||||
// Truncated ciphertext, but with correct auth tag
|
||||
truncated, tail := resize(ct[:len(ct)-ctx.authtagBytes-2], len(ct)-2)
|
||||
copy(tail, ctx.computeAuthTag(nil, nonce, truncated[:len(truncated)-ctx.authtagBytes]))
|
||||
|
||||
// Open should fail
|
||||
_, err = aead.Open(nil, nonce, truncated, nil)
|
||||
if err == nil {
|
||||
t.Error("open on truncated ciphertext should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidPaddingOpen(t *testing.T) {
|
||||
key := make([]byte, 32)
|
||||
nonce := make([]byte, 16)
|
||||
|
||||
// Plaintext with invalid padding
|
||||
plaintext := padBuffer(make([]byte, 28), aes.BlockSize)
|
||||
plaintext[len(plaintext)-1] = 0xFF
|
||||
|
||||
io.ReadFull(rand.Reader, key)
|
||||
io.ReadFull(rand.Reader, nonce)
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
cbc := cipher.NewCBCEncrypter(block, nonce)
|
||||
buffer := append([]byte{}, plaintext...)
|
||||
cbc.CryptBlocks(buffer, buffer)
|
||||
|
||||
aead, _ := NewCBCHMAC(key, aes.NewCipher)
|
||||
ctx := aead.(*cbcAEAD)
|
||||
|
||||
// Mutated ciphertext, but with correct auth tag
|
||||
size := len(buffer)
|
||||
ciphertext, tail := resize(buffer, size+(len(key)/2))
|
||||
copy(tail, ctx.computeAuthTag(nil, nonce, ciphertext[:size]))
|
||||
|
||||
// Open should fail (b/c of invalid padding, even though tag matches)
|
||||
_, err := aead.Open(nil, nonce, ciphertext, nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid padding") {
|
||||
t.Error("no or unexpected error on open with invalid padding:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidPadding(t *testing.T) {
|
||||
for i := 0; i < 256; i++ {
|
||||
slice := make([]byte, i)
|
||||
padded := padBuffer(slice, 16)
|
||||
if len(padded)%16 != 0 {
|
||||
t.Error("failed to pad slice properly", i)
|
||||
return
|
||||
}
|
||||
|
||||
paddingBytes := 16 - (i % 16)
|
||||
|
||||
// Mutate padding for testing
|
||||
for j := 1; j <= paddingBytes; j++ {
|
||||
mutated := make([]byte, len(padded))
|
||||
copy(mutated, padded)
|
||||
mutated[len(mutated)-j] ^= 0xFF
|
||||
|
||||
_, err := unpadBuffer(mutated, 16)
|
||||
if err == nil {
|
||||
t.Error("unpad on invalid padding should fail", i)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Test truncated padding
|
||||
_, err := unpadBuffer(padded[:len(padded)-1], 16)
|
||||
if err == nil {
|
||||
t.Error("unpad on truncated padding should fail", i)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestZeroLengthPadding(t *testing.T) {
|
||||
data := make([]byte, 16)
|
||||
data, err := unpadBuffer(data, 16)
|
||||
if err == nil {
|
||||
t.Error("padding with 0x00 should never be valid")
|
||||
}
|
||||
}
|
||||
|
||||
func benchEncryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
|
||||
key := make([]byte, keySize*2)
|
||||
nonce := make([]byte, 16)
|
||||
|
||||
io.ReadFull(rand.Reader, key)
|
||||
io.ReadFull(rand.Reader, nonce)
|
||||
|
||||
chunk := make([]byte, chunkSize)
|
||||
|
||||
aead, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
b.SetBytes(int64(chunkSize))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
aead.Seal(nil, nonce, chunk, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func benchDecryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
|
||||
key := make([]byte, keySize*2)
|
||||
nonce := make([]byte, 16)
|
||||
|
||||
io.ReadFull(rand.Reader, key)
|
||||
io.ReadFull(rand.Reader, nonce)
|
||||
|
||||
chunk := make([]byte, chunkSize)
|
||||
|
||||
aead, err := NewCBCHMAC(key, aes.NewCipher)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := aead.Seal(nil, nonce, chunk, nil)
|
||||
|
||||
b.SetBytes(int64(chunkSize))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
aead.Open(nil, nonce, out, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES128_CBCHMAC_1k(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 16, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES128_CBCHMAC_64k(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 16, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES128_CBCHMAC_1MB(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 16, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES128_CBCHMAC_64MB(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 16, 67108864)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES128_CBCHMAC_1k(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 16, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES128_CBCHMAC_64k(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 16, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES128_CBCHMAC_1MB(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 16, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES128_CBCHMAC_64MB(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 16, 67108864)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES192_CBCHMAC_64k(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 24, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES192_CBCHMAC_1MB(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 24, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES192_CBCHMAC_64MB(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 24, 67108864)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES192_CBCHMAC_1k(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 24, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES192_CBCHMAC_64k(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 24, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES192_CBCHMAC_1MB(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 24, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES192_CBCHMAC_64MB(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 24, 67108864)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES256_CBCHMAC_64k(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 32, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES256_CBCHMAC_1MB(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 32, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkEncryptAES256_CBCHMAC_64MB(b *testing.B) {
|
||||
benchEncryptCBCHMAC(b, 32, 67108864)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES256_CBCHMAC_1k(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 32, 1032)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES256_CBCHMAC_64k(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 32, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES256_CBCHMAC_1MB(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 32, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkDecryptAES256_CBCHMAC_64MB(b *testing.B) {
|
||||
benchDecryptCBCHMAC(b, 32, 67108864)
|
||||
}
|
||||
148
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/concat_kdf_test.go
generated
vendored
Normal file
148
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/concat_kdf_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package josecipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Taken from: https://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-38.txt
|
||||
func TestVectorConcatKDF(t *testing.T) {
|
||||
z := []byte{
|
||||
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
|
||||
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
|
||||
140, 254, 144, 196}
|
||||
|
||||
algID := []byte{0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77}
|
||||
|
||||
ptyUInfo := []byte{0, 0, 0, 5, 65, 108, 105, 99, 101}
|
||||
ptyVInfo := []byte{0, 0, 0, 3, 66, 111, 98}
|
||||
|
||||
supPubInfo := []byte{0, 0, 0, 128}
|
||||
supPrivInfo := []byte{}
|
||||
|
||||
expected := []byte{
|
||||
86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26}
|
||||
|
||||
ckdf := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
|
||||
|
||||
out0 := make([]byte, 9)
|
||||
out1 := make([]byte, 7)
|
||||
|
||||
read0, err := ckdf.Read(out0)
|
||||
if err != nil {
|
||||
t.Error("error when reading from concat kdf reader", err)
|
||||
return
|
||||
}
|
||||
|
||||
read1, err := ckdf.Read(out1)
|
||||
if err != nil {
|
||||
t.Error("error when reading from concat kdf reader", err)
|
||||
return
|
||||
}
|
||||
|
||||
if read0+read1 != len(out0)+len(out1) {
|
||||
t.Error("did not receive enough bytes from concat kdf reader")
|
||||
return
|
||||
}
|
||||
|
||||
out := []byte{}
|
||||
out = append(out, out0...)
|
||||
out = append(out, out1...)
|
||||
|
||||
if bytes.Compare(out, expected) != 0 {
|
||||
t.Error("did not receive expected output from concat kdf reader")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
z := []byte{
|
||||
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
|
||||
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
|
||||
140, 254, 144, 196}
|
||||
|
||||
algID := []byte{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}
|
||||
|
||||
ptyUInfo := []byte{1, 2, 3, 4}
|
||||
ptyVInfo := []byte{4, 3, 2, 1}
|
||||
|
||||
supPubInfo := []byte{}
|
||||
supPrivInfo := []byte{}
|
||||
|
||||
outputs := [][]byte{}
|
||||
|
||||
// Read the same amount of data in different chunk sizes
|
||||
for i := 10; i <= 100; i++ {
|
||||
out := make([]byte, 1024)
|
||||
reader := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
|
||||
|
||||
for j := 0; j < 1024/i; j++ {
|
||||
_, _ = reader.Read(out[j*i:])
|
||||
}
|
||||
|
||||
outputs = append(outputs, out)
|
||||
}
|
||||
|
||||
for i := range outputs {
|
||||
if bytes.Compare(outputs[i], outputs[i%len(outputs)]) != 0 {
|
||||
t.Error("not all outputs from KDF matched")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkKDF(b *testing.B, total int) {
|
||||
z := []byte{
|
||||
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
|
||||
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
|
||||
140, 254, 144, 196}
|
||||
|
||||
algID := []byte{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}
|
||||
|
||||
ptyUInfo := []byte{1, 2, 3, 4}
|
||||
ptyVInfo := []byte{4, 3, 2, 1}
|
||||
|
||||
supPubInfo := []byte{}
|
||||
supPrivInfo := []byte{}
|
||||
|
||||
out := make([]byte, total)
|
||||
reader := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
|
||||
|
||||
b.ResetTimer()
|
||||
b.SetBytes(int64(total))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = reader.Read(out)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConcatKDF_1k(b *testing.B) {
|
||||
benchmarkKDF(b, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkConcatKDF_64k(b *testing.B) {
|
||||
benchmarkKDF(b, 65536)
|
||||
}
|
||||
|
||||
func BenchmarkConcatKDF_1MB(b *testing.B) {
|
||||
benchmarkKDF(b, 1048576)
|
||||
}
|
||||
|
||||
func BenchmarkConcatKDF_64MB(b *testing.B) {
|
||||
benchmarkKDF(b, 67108864)
|
||||
}
|
||||
98
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/ecdh_es_test.go
generated
vendored
Normal file
98
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/ecdh_es_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package josecipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"encoding/base64"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Example keys from JWA, Appendix C
|
||||
var aliceKey = &ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
Curve: elliptic.P256(),
|
||||
X: fromBase64Int("gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0="),
|
||||
Y: fromBase64Int("SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps="),
|
||||
},
|
||||
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo="),
|
||||
}
|
||||
|
||||
var bobKey = &ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
Curve: elliptic.P256(),
|
||||
X: fromBase64Int("weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ="),
|
||||
Y: fromBase64Int("e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck="),
|
||||
},
|
||||
D: fromBase64Int("VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw="),
|
||||
}
|
||||
|
||||
// Build big int from base64-encoded string. Strips whitespace (for testing).
|
||||
func fromBase64Int(data string) *big.Int {
|
||||
val, err := base64.URLEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
panic("Invalid test data")
|
||||
}
|
||||
return new(big.Int).SetBytes(val)
|
||||
}
|
||||
|
||||
func TestVectorECDHES(t *testing.T) {
|
||||
apuData := []byte("Alice")
|
||||
apvData := []byte("Bob")
|
||||
|
||||
expected := []byte{
|
||||
86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26}
|
||||
|
||||
output := DeriveECDHES("A128GCM", apuData, apvData, bobKey, &aliceKey.PublicKey, 16)
|
||||
|
||||
if bytes.Compare(output, expected) != 0 {
|
||||
t.Error("output did not match what we expect, got", output, "wanted", expected)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkECDHES_128(b *testing.B) {
|
||||
apuData := []byte("APU")
|
||||
apvData := []byte("APV")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 16)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkECDHES_192(b *testing.B) {
|
||||
apuData := []byte("APU")
|
||||
apvData := []byte("APV")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 24)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkECDHES_256(b *testing.B) {
|
||||
apuData := []byte("APU")
|
||||
apvData := []byte("APV")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 32)
|
||||
}
|
||||
}
|
||||
133
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/key_wrap_test.go
generated
vendored
Normal file
133
Godeps/_workspace/src/github.com/letsencrypt/go-jose/cipher/key_wrap_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package josecipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAesKeyWrap(t *testing.T) {
|
||||
// Test vectors from: http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
|
||||
kek0, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
|
||||
cek0, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF")
|
||||
|
||||
expected0, _ := hex.DecodeString("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5")
|
||||
|
||||
kek1, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F1011121314151617")
|
||||
cek1, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF")
|
||||
|
||||
expected1, _ := hex.DecodeString("96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D")
|
||||
|
||||
kek2, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")
|
||||
cek2, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF0001020304050607")
|
||||
|
||||
expected2, _ := hex.DecodeString("A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1")
|
||||
|
||||
block0, _ := aes.NewCipher(kek0)
|
||||
block1, _ := aes.NewCipher(kek1)
|
||||
block2, _ := aes.NewCipher(kek2)
|
||||
|
||||
out0, _ := KeyWrap(block0, cek0)
|
||||
out1, _ := KeyWrap(block1, cek1)
|
||||
out2, _ := KeyWrap(block2, cek2)
|
||||
|
||||
if bytes.Compare(out0, expected0) != 0 {
|
||||
t.Error("output 0 not as expected, got", out0, "wanted", expected0)
|
||||
}
|
||||
|
||||
if bytes.Compare(out1, expected1) != 0 {
|
||||
t.Error("output 1 not as expected, got", out1, "wanted", expected1)
|
||||
}
|
||||
|
||||
if bytes.Compare(out2, expected2) != 0 {
|
||||
t.Error("output 2 not as expected, got", out2, "wanted", expected2)
|
||||
}
|
||||
|
||||
unwrap0, _ := KeyUnwrap(block0, out0)
|
||||
unwrap1, _ := KeyUnwrap(block1, out1)
|
||||
unwrap2, _ := KeyUnwrap(block2, out2)
|
||||
|
||||
if bytes.Compare(unwrap0, cek0) != 0 {
|
||||
t.Error("key unwrap did not return original input, got", unwrap0, "wanted", cek0)
|
||||
}
|
||||
|
||||
if bytes.Compare(unwrap1, cek1) != 0 {
|
||||
t.Error("key unwrap did not return original input, got", unwrap1, "wanted", cek1)
|
||||
}
|
||||
|
||||
if bytes.Compare(unwrap2, cek2) != 0 {
|
||||
t.Error("key unwrap did not return original input, got", unwrap2, "wanted", cek2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAesKeyWrapInvalid(t *testing.T) {
|
||||
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
|
||||
|
||||
// Invalid unwrap input (bit flipped)
|
||||
input0, _ := hex.DecodeString("1EA68C1A8112B447AEF34BD8FB5A7B828D3E862371D2CFE5")
|
||||
|
||||
block, _ := aes.NewCipher(kek)
|
||||
|
||||
_, err := KeyUnwrap(block, input0)
|
||||
if err == nil {
|
||||
t.Error("key unwrap failed to detect invalid input")
|
||||
}
|
||||
|
||||
// Invalid unwrap input (truncated)
|
||||
input1, _ := hex.DecodeString("1EA68C1A8112B447AEF34BD8FB5A7B828D3E862371D2CF")
|
||||
|
||||
_, err = KeyUnwrap(block, input1)
|
||||
if err == nil {
|
||||
t.Error("key unwrap failed to detect truncated input")
|
||||
}
|
||||
|
||||
// Invalid wrap input (not multiple of 8)
|
||||
input2, _ := hex.DecodeString("0123456789ABCD")
|
||||
|
||||
_, err = KeyWrap(block, input2)
|
||||
if err == nil {
|
||||
t.Error("key wrap accepted invalid input")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkAesKeyWrap(b *testing.B) {
|
||||
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
|
||||
key, _ := hex.DecodeString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||
|
||||
block, _ := aes.NewCipher(kek)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
KeyWrap(block, key)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAesKeyUnwrap(b *testing.B) {
|
||||
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
|
||||
input, _ := hex.DecodeString("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5")
|
||||
|
||||
block, _ := aes.NewCipher(kek)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
KeyUnwrap(block, input)
|
||||
}
|
||||
}
|
||||
751
Godeps/_workspace/src/github.com/letsencrypt/go-jose/crypter_test.go
generated
vendored
Normal file
751
Godeps/_workspace/src/github.com/letsencrypt/go-jose/crypter_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,751 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// We generate only a single RSA and EC key for testing, speeds up tests.
|
||||
var rsaTestKey, _ = rsa.GenerateKey(rand.Reader, 2048)
|
||||
|
||||
var ecTestKey256, _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
var ecTestKey384, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
var ecTestKey521, _ = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
|
||||
func RoundtripJWE(keyAlg KeyAlgorithm, encAlg ContentEncryption, compressionAlg CompressionAlgorithm, serializer func(*JsonWebEncryption) (string, error), corrupter func(*JsonWebEncryption) bool, aad []byte, encryptionKey interface{}, decryptionKey interface{}) error {
|
||||
enc, err := NewEncrypter(keyAlg, encAlg, encryptionKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on new encrypter: %s", err)
|
||||
}
|
||||
|
||||
enc.SetCompression(compressionAlg)
|
||||
|
||||
input := []byte("Lorem ipsum dolor sit amet")
|
||||
obj, err := enc.EncryptWithAuthData(input, aad)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in encrypt: %s", err)
|
||||
}
|
||||
|
||||
msg, err := serializer(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in serializer: %s", err)
|
||||
}
|
||||
|
||||
parsed, err := ParseEncrypted(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in parse: %s, on msg '%s'", err, msg)
|
||||
}
|
||||
|
||||
// (Maybe) mangle object
|
||||
skip := corrupter(parsed)
|
||||
if skip {
|
||||
return fmt.Errorf("corrupter indicated message should be skipped")
|
||||
}
|
||||
|
||||
if bytes.Compare(parsed.GetAuthData(), aad) != 0 {
|
||||
return fmt.Errorf("auth data in parsed object does not match")
|
||||
}
|
||||
|
||||
output, err := parsed.Decrypt(decryptionKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on decrypt: %s", err)
|
||||
}
|
||||
|
||||
if bytes.Compare(input, output) != 0 {
|
||||
return fmt.Errorf("Decrypted output does not match input, got '%s' but wanted '%s'", output, input)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRoundtripsJWE(t *testing.T) {
|
||||
// Test matrix
|
||||
keyAlgs := []KeyAlgorithm{
|
||||
DIRECT, ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW, A128KW, A192KW, A256KW,
|
||||
RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW, A192GCMKW, A256GCMKW}
|
||||
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
|
||||
zipAlgs := []CompressionAlgorithm{NONE, DEFLATE}
|
||||
|
||||
serializers := []func(*JsonWebEncryption) (string, error){
|
||||
func(obj *JsonWebEncryption) (string, error) { return obj.CompactSerialize() },
|
||||
func(obj *JsonWebEncryption) (string, error) { return obj.FullSerialize(), nil },
|
||||
}
|
||||
|
||||
corrupter := func(obj *JsonWebEncryption) bool { return false }
|
||||
|
||||
// Note: can't use AAD with compact serialization
|
||||
aads := [][]byte{
|
||||
nil,
|
||||
[]byte("Ut enim ad minim veniam"),
|
||||
}
|
||||
|
||||
// Test all different configurations
|
||||
for _, alg := range keyAlgs {
|
||||
for _, enc := range encAlgs {
|
||||
for _, key := range generateTestKeys(alg, enc) {
|
||||
for _, zip := range zipAlgs {
|
||||
for i, serializer := range serializers {
|
||||
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, aads[i], key.enc, key.dec)
|
||||
if err != nil {
|
||||
t.Error(err, alg, enc, zip, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundtripsJWECorrupted(t *testing.T) {
|
||||
// Test matrix
|
||||
keyAlgs := []KeyAlgorithm{DIRECT, ECDH_ES, ECDH_ES_A128KW, A128KW, RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW}
|
||||
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
|
||||
zipAlgs := []CompressionAlgorithm{NONE, DEFLATE}
|
||||
|
||||
serializers := []func(*JsonWebEncryption) (string, error){
|
||||
func(obj *JsonWebEncryption) (string, error) { return obj.CompactSerialize() },
|
||||
func(obj *JsonWebEncryption) (string, error) { return obj.FullSerialize(), nil },
|
||||
}
|
||||
|
||||
bitflip := func(slice []byte) bool {
|
||||
if len(slice) > 0 {
|
||||
slice[0] ^= 0xFF
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
corrupters := []func(*JsonWebEncryption) bool{
|
||||
func(obj *JsonWebEncryption) bool {
|
||||
// Set invalid ciphertext
|
||||
return bitflip(obj.ciphertext)
|
||||
},
|
||||
func(obj *JsonWebEncryption) bool {
|
||||
// Set invalid auth tag
|
||||
return bitflip(obj.tag)
|
||||
},
|
||||
func(obj *JsonWebEncryption) bool {
|
||||
// Set invalid AAD
|
||||
return bitflip(obj.aad)
|
||||
},
|
||||
func(obj *JsonWebEncryption) bool {
|
||||
// Mess with encrypted key
|
||||
return bitflip(obj.recipients[0].encryptedKey)
|
||||
},
|
||||
func(obj *JsonWebEncryption) bool {
|
||||
// Mess with GCM-KW auth tag
|
||||
return bitflip(obj.protected.Tag.bytes())
|
||||
},
|
||||
}
|
||||
|
||||
// Note: can't use AAD with compact serialization
|
||||
aads := [][]byte{
|
||||
nil,
|
||||
[]byte("Ut enim ad minim veniam"),
|
||||
}
|
||||
|
||||
// Test all different configurations
|
||||
for _, alg := range keyAlgs {
|
||||
for _, enc := range encAlgs {
|
||||
for _, key := range generateTestKeys(alg, enc) {
|
||||
for _, zip := range zipAlgs {
|
||||
for i, serializer := range serializers {
|
||||
for j, corrupter := range corrupters {
|
||||
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, aads[i], key.enc, key.dec)
|
||||
if err == nil {
|
||||
t.Error("failed to detect corrupt data", err, alg, enc, zip, i, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncrypterWithBrokenRand(t *testing.T) {
|
||||
keyAlgs := []KeyAlgorithm{ECDH_ES_A128KW, A128KW, RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW}
|
||||
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
|
||||
|
||||
serializer := func(obj *JsonWebEncryption) (string, error) { return obj.CompactSerialize() }
|
||||
corrupter := func(obj *JsonWebEncryption) bool { return false }
|
||||
|
||||
// Break rand reader
|
||||
readers := []func() io.Reader{
|
||||
// Totally broken
|
||||
func() io.Reader { return bytes.NewReader([]byte{}) },
|
||||
// Not enough bytes
|
||||
func() io.Reader { return io.LimitReader(rand.Reader, 20) },
|
||||
}
|
||||
|
||||
defer resetRandReader()
|
||||
|
||||
for _, alg := range keyAlgs {
|
||||
for _, enc := range encAlgs {
|
||||
for _, key := range generateTestKeys(alg, enc) {
|
||||
for i, getReader := range readers {
|
||||
randReader = getReader()
|
||||
err := RoundtripJWE(alg, enc, NONE, serializer, corrupter, nil, key.enc, key.dec)
|
||||
if err == nil {
|
||||
t.Error("encrypter should fail if rand is broken", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewEncrypterErrors(t *testing.T) {
|
||||
_, err := NewEncrypter("XYZ", "XYZ", nil)
|
||||
if err == nil {
|
||||
t.Error("was able to instantiate encrypter with invalid cipher")
|
||||
}
|
||||
|
||||
_, err = NewMultiEncrypter("XYZ")
|
||||
if err == nil {
|
||||
t.Error("was able to instantiate multi-encrypter with invalid cipher")
|
||||
}
|
||||
|
||||
_, err = NewEncrypter(DIRECT, A128GCM, nil)
|
||||
if err == nil {
|
||||
t.Error("was able to instantiate encrypter with invalid direct key")
|
||||
}
|
||||
|
||||
_, err = NewEncrypter(ECDH_ES, A128GCM, nil)
|
||||
if err == nil {
|
||||
t.Error("was able to instantiate encrypter with invalid EC key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRecipientJWE(t *testing.T) {
|
||||
enc, err := NewMultiEncrypter(A128GCM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = enc.AddRecipient(RSA_OAEP, &rsaTestKey.PublicKey)
|
||||
if err != nil {
|
||||
t.Error("error when adding RSA recipient", err)
|
||||
}
|
||||
|
||||
sharedKey := []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
}
|
||||
|
||||
err = enc.AddRecipient(A256GCMKW, sharedKey)
|
||||
if err != nil {
|
||||
t.Error("error when adding AES recipient: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
input := []byte("Lorem ipsum dolor sit amet")
|
||||
obj, err := enc.Encrypt(input)
|
||||
if err != nil {
|
||||
t.Error("error in encrypt: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
msg := obj.FullSerialize()
|
||||
|
||||
parsed, err := ParseEncrypted(msg)
|
||||
if err != nil {
|
||||
t.Error("error in parse: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
output, err := parsed.Decrypt(rsaTestKey)
|
||||
if err != nil {
|
||||
t.Error("error on decrypt with RSA: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(input, output) != 0 {
|
||||
t.Error("Decrypted output does not match input: ", output, input)
|
||||
return
|
||||
}
|
||||
|
||||
output, err = parsed.Decrypt(sharedKey)
|
||||
if err != nil {
|
||||
t.Error("error on decrypt with AES: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(input, output) != 0 {
|
||||
t.Error("Decrypted output does not match input", output, input)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRecipientErrors(t *testing.T) {
|
||||
enc, err := NewMultiEncrypter(A128GCM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
input := []byte("Lorem ipsum dolor sit amet")
|
||||
_, err = enc.Encrypt(input)
|
||||
if err == nil {
|
||||
t.Error("should fail when encrypting to zero recipients")
|
||||
}
|
||||
|
||||
err = enc.AddRecipient(DIRECT, nil)
|
||||
if err == nil {
|
||||
t.Error("should reject DIRECT mode when encrypting to multiple recipients")
|
||||
}
|
||||
|
||||
err = enc.AddRecipient(ECDH_ES, nil)
|
||||
if err == nil {
|
||||
t.Error("should reject ECDH_ES mode when encrypting to multiple recipients")
|
||||
}
|
||||
|
||||
err = enc.AddRecipient(RSA1_5, nil)
|
||||
if err == nil {
|
||||
t.Error("should reject invalid recipient key")
|
||||
}
|
||||
}
|
||||
|
||||
type testKey struct {
|
||||
enc, dec interface{}
|
||||
}
|
||||
|
||||
func symmetricTestKey(size int) []testKey {
|
||||
key, _, _ := randomKeyGenerator{size: size}.genKey()
|
||||
|
||||
return []testKey{
|
||||
testKey{
|
||||
enc: key,
|
||||
dec: key,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateTestKeys(keyAlg KeyAlgorithm, encAlg ContentEncryption) []testKey {
|
||||
switch keyAlg {
|
||||
case DIRECT:
|
||||
return symmetricTestKey(getContentCipher(encAlg).keySize())
|
||||
case ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
|
||||
return []testKey{
|
||||
testKey{
|
||||
dec: ecTestKey256,
|
||||
enc: &ecTestKey256.PublicKey,
|
||||
},
|
||||
testKey{
|
||||
dec: ecTestKey384,
|
||||
enc: &ecTestKey384.PublicKey,
|
||||
},
|
||||
testKey{
|
||||
dec: ecTestKey521,
|
||||
enc: &ecTestKey521.PublicKey,
|
||||
},
|
||||
}
|
||||
case A128GCMKW, A128KW:
|
||||
return symmetricTestKey(16)
|
||||
case A192GCMKW, A192KW:
|
||||
return symmetricTestKey(24)
|
||||
case A256GCMKW, A256KW:
|
||||
return symmetricTestKey(32)
|
||||
case RSA1_5, RSA_OAEP, RSA_OAEP_256:
|
||||
return []testKey{testKey{
|
||||
dec: rsaTestKey,
|
||||
enc: &rsaTestKey.PublicKey,
|
||||
}}
|
||||
}
|
||||
|
||||
panic("Must update test case")
|
||||
}
|
||||
|
||||
func RunRoundtripsJWE(b *testing.B, alg KeyAlgorithm, enc ContentEncryption, zip CompressionAlgorithm, priv, pub interface{}) {
|
||||
serializer := func(obj *JsonWebEncryption) (string, error) {
|
||||
return obj.CompactSerialize()
|
||||
}
|
||||
|
||||
corrupter := func(obj *JsonWebEncryption) bool { return false }
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, nil, pub, priv)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
chunks = map[string][]byte{
|
||||
"1B": make([]byte, 1),
|
||||
"64B": make([]byte, 64),
|
||||
"1KB": make([]byte, 1024),
|
||||
"64KB": make([]byte, 65536),
|
||||
"1MB": make([]byte, 1048576),
|
||||
"64MB": make([]byte, 67108864),
|
||||
}
|
||||
|
||||
symKey, _, _ = randomKeyGenerator{size: 32}.genKey()
|
||||
|
||||
encrypters = map[string]Encrypter{
|
||||
"OAEPAndGCM": mustEncrypter(RSA_OAEP, A128GCM, &rsaTestKey.PublicKey),
|
||||
"PKCSAndGCM": mustEncrypter(RSA1_5, A128GCM, &rsaTestKey.PublicKey),
|
||||
"OAEPAndCBC": mustEncrypter(RSA_OAEP, A128CBC_HS256, &rsaTestKey.PublicKey),
|
||||
"PKCSAndCBC": mustEncrypter(RSA1_5, A128CBC_HS256, &rsaTestKey.PublicKey),
|
||||
"DirectGCM128": mustEncrypter(DIRECT, A128GCM, symKey),
|
||||
"DirectCBC128": mustEncrypter(DIRECT, A128CBC_HS256, symKey),
|
||||
"DirectGCM256": mustEncrypter(DIRECT, A256GCM, symKey),
|
||||
"DirectCBC256": mustEncrypter(DIRECT, A256CBC_HS512, symKey),
|
||||
"AESKWAndGCM128": mustEncrypter(A128KW, A128GCM, symKey),
|
||||
"AESKWAndCBC256": mustEncrypter(A256KW, A256GCM, symKey),
|
||||
"ECDHOnP256AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey256.PublicKey),
|
||||
"ECDHOnP384AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey384.PublicKey),
|
||||
"ECDHOnP521AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey521.PublicKey),
|
||||
}
|
||||
)
|
||||
|
||||
func BenchmarkEncrypt1BWithOAEPAndGCM(b *testing.B) { benchEncrypt("1B", "OAEPAndGCM", b) }
|
||||
func BenchmarkEncrypt64BWithOAEPAndGCM(b *testing.B) { benchEncrypt("64B", "OAEPAndGCM", b) }
|
||||
func BenchmarkEncrypt1KBWithOAEPAndGCM(b *testing.B) { benchEncrypt("1KB", "OAEPAndGCM", b) }
|
||||
func BenchmarkEncrypt64KBWithOAEPAndGCM(b *testing.B) { benchEncrypt("64KB", "OAEPAndGCM", b) }
|
||||
func BenchmarkEncrypt1MBWithOAEPAndGCM(b *testing.B) { benchEncrypt("1MB", "OAEPAndGCM", b) }
|
||||
func BenchmarkEncrypt64MBWithOAEPAndGCM(b *testing.B) { benchEncrypt("64MB", "OAEPAndGCM", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithPKCSAndGCM(b *testing.B) { benchEncrypt("1B", "PKCSAndGCM", b) }
|
||||
func BenchmarkEncrypt64BWithPKCSAndGCM(b *testing.B) { benchEncrypt("64B", "PKCSAndGCM", b) }
|
||||
func BenchmarkEncrypt1KBWithPKCSAndGCM(b *testing.B) { benchEncrypt("1KB", "PKCSAndGCM", b) }
|
||||
func BenchmarkEncrypt64KBWithPKCSAndGCM(b *testing.B) { benchEncrypt("64KB", "PKCSAndGCM", b) }
|
||||
func BenchmarkEncrypt1MBWithPKCSAndGCM(b *testing.B) { benchEncrypt("1MB", "PKCSAndGCM", b) }
|
||||
func BenchmarkEncrypt64MBWithPKCSAndGCM(b *testing.B) { benchEncrypt("64MB", "PKCSAndGCM", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithOAEPAndCBC(b *testing.B) { benchEncrypt("1B", "OAEPAndCBC", b) }
|
||||
func BenchmarkEncrypt64BWithOAEPAndCBC(b *testing.B) { benchEncrypt("64B", "OAEPAndCBC", b) }
|
||||
func BenchmarkEncrypt1KBWithOAEPAndCBC(b *testing.B) { benchEncrypt("1KB", "OAEPAndCBC", b) }
|
||||
func BenchmarkEncrypt64KBWithOAEPAndCBC(b *testing.B) { benchEncrypt("64KB", "OAEPAndCBC", b) }
|
||||
func BenchmarkEncrypt1MBWithOAEPAndCBC(b *testing.B) { benchEncrypt("1MB", "OAEPAndCBC", b) }
|
||||
func BenchmarkEncrypt64MBWithOAEPAndCBC(b *testing.B) { benchEncrypt("64MB", "OAEPAndCBC", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithPKCSAndCBC(b *testing.B) { benchEncrypt("1B", "PKCSAndCBC", b) }
|
||||
func BenchmarkEncrypt64BWithPKCSAndCBC(b *testing.B) { benchEncrypt("64B", "PKCSAndCBC", b) }
|
||||
func BenchmarkEncrypt1KBWithPKCSAndCBC(b *testing.B) { benchEncrypt("1KB", "PKCSAndCBC", b) }
|
||||
func BenchmarkEncrypt64KBWithPKCSAndCBC(b *testing.B) { benchEncrypt("64KB", "PKCSAndCBC", b) }
|
||||
func BenchmarkEncrypt1MBWithPKCSAndCBC(b *testing.B) { benchEncrypt("1MB", "PKCSAndCBC", b) }
|
||||
func BenchmarkEncrypt64MBWithPKCSAndCBC(b *testing.B) { benchEncrypt("64MB", "PKCSAndCBC", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithDirectGCM128(b *testing.B) { benchEncrypt("1B", "DirectGCM128", b) }
|
||||
func BenchmarkEncrypt64BWithDirectGCM128(b *testing.B) { benchEncrypt("64B", "DirectGCM128", b) }
|
||||
func BenchmarkEncrypt1KBWithDirectGCM128(b *testing.B) { benchEncrypt("1KB", "DirectGCM128", b) }
|
||||
func BenchmarkEncrypt64KBWithDirectGCM128(b *testing.B) { benchEncrypt("64KB", "DirectGCM128", b) }
|
||||
func BenchmarkEncrypt1MBWithDirectGCM128(b *testing.B) { benchEncrypt("1MB", "DirectGCM128", b) }
|
||||
func BenchmarkEncrypt64MBWithDirectGCM128(b *testing.B) { benchEncrypt("64MB", "DirectGCM128", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithDirectCBC128(b *testing.B) { benchEncrypt("1B", "DirectCBC128", b) }
|
||||
func BenchmarkEncrypt64BWithDirectCBC128(b *testing.B) { benchEncrypt("64B", "DirectCBC128", b) }
|
||||
func BenchmarkEncrypt1KBWithDirectCBC128(b *testing.B) { benchEncrypt("1KB", "DirectCBC128", b) }
|
||||
func BenchmarkEncrypt64KBWithDirectCBC128(b *testing.B) { benchEncrypt("64KB", "DirectCBC128", b) }
|
||||
func BenchmarkEncrypt1MBWithDirectCBC128(b *testing.B) { benchEncrypt("1MB", "DirectCBC128", b) }
|
||||
func BenchmarkEncrypt64MBWithDirectCBC128(b *testing.B) { benchEncrypt("64MB", "DirectCBC128", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithDirectGCM256(b *testing.B) { benchEncrypt("1B", "DirectGCM256", b) }
|
||||
func BenchmarkEncrypt64BWithDirectGCM256(b *testing.B) { benchEncrypt("64B", "DirectGCM256", b) }
|
||||
func BenchmarkEncrypt1KBWithDirectGCM256(b *testing.B) { benchEncrypt("1KB", "DirectGCM256", b) }
|
||||
func BenchmarkEncrypt64KBWithDirectGCM256(b *testing.B) { benchEncrypt("64KB", "DirectGCM256", b) }
|
||||
func BenchmarkEncrypt1MBWithDirectGCM256(b *testing.B) { benchEncrypt("1MB", "DirectGCM256", b) }
|
||||
func BenchmarkEncrypt64MBWithDirectGCM256(b *testing.B) { benchEncrypt("64MB", "DirectGCM256", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithDirectCBC256(b *testing.B) { benchEncrypt("1B", "DirectCBC256", b) }
|
||||
func BenchmarkEncrypt64BWithDirectCBC256(b *testing.B) { benchEncrypt("64B", "DirectCBC256", b) }
|
||||
func BenchmarkEncrypt1KBWithDirectCBC256(b *testing.B) { benchEncrypt("1KB", "DirectCBC256", b) }
|
||||
func BenchmarkEncrypt64KBWithDirectCBC256(b *testing.B) { benchEncrypt("64KB", "DirectCBC256", b) }
|
||||
func BenchmarkEncrypt1MBWithDirectCBC256(b *testing.B) { benchEncrypt("1MB", "DirectCBC256", b) }
|
||||
func BenchmarkEncrypt64MBWithDirectCBC256(b *testing.B) { benchEncrypt("64MB", "DirectCBC256", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1B", "AESKWAndGCM128", b) }
|
||||
func BenchmarkEncrypt64BWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64B", "AESKWAndGCM128", b) }
|
||||
func BenchmarkEncrypt1KBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1KB", "AESKWAndGCM128", b) }
|
||||
func BenchmarkEncrypt64KBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64KB", "AESKWAndGCM128", b) }
|
||||
func BenchmarkEncrypt1MBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1MB", "AESKWAndGCM128", b) }
|
||||
func BenchmarkEncrypt64MBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64MB", "AESKWAndGCM128", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1B", "AESKWAndCBC256", b) }
|
||||
func BenchmarkEncrypt64BWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64B", "AESKWAndCBC256", b) }
|
||||
func BenchmarkEncrypt1KBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1KB", "AESKWAndCBC256", b) }
|
||||
func BenchmarkEncrypt64KBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64KB", "AESKWAndCBC256", b) }
|
||||
func BenchmarkEncrypt1MBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1MB", "AESKWAndCBC256", b) }
|
||||
func BenchmarkEncrypt64MBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64MB", "AESKWAndCBC256", b) }
|
||||
|
||||
func BenchmarkEncrypt1BWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1B", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64BWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64B", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt1KBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1KB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64KBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64KB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt1MBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1MB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64MBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64MB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
|
||||
func BenchmarkEncrypt1BWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1B", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64BWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64B", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt1KBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1KB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64KBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64KB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt1MBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1MB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64MBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64MB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
|
||||
func BenchmarkEncrypt1BWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1B", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64BWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64B", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt1KBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1KB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64KBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64KB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt1MBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchEncrypt("1MB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkEncrypt64MBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchEncrypt("64MB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
|
||||
func benchEncrypt(chunkKey, primKey string, b *testing.B) {
|
||||
data, ok := chunks[chunkKey]
|
||||
if !ok {
|
||||
b.Fatalf("unknown chunk size %s", chunkKey)
|
||||
}
|
||||
|
||||
enc, ok := encrypters[primKey]
|
||||
if !ok {
|
||||
b.Fatalf("unknown encrypter %s", primKey)
|
||||
}
|
||||
|
||||
b.SetBytes(int64(len(data)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
enc.Encrypt(data)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
decryptionKeys = map[string]interface{}{
|
||||
"OAEPAndGCM": rsaTestKey,
|
||||
"PKCSAndGCM": rsaTestKey,
|
||||
"OAEPAndCBC": rsaTestKey,
|
||||
"PKCSAndCBC": rsaTestKey,
|
||||
|
||||
"DirectGCM128": symKey,
|
||||
"DirectCBC128": symKey,
|
||||
"DirectGCM256": symKey,
|
||||
"DirectCBC256": symKey,
|
||||
|
||||
"AESKWAndGCM128": symKey,
|
||||
"AESKWAndCBC256": symKey,
|
||||
|
||||
"ECDHOnP256AndGCM128": ecTestKey256,
|
||||
"ECDHOnP384AndGCM128": ecTestKey384,
|
||||
"ECDHOnP521AndGCM128": ecTestKey521,
|
||||
}
|
||||
)
|
||||
|
||||
func BenchmarkDecrypt1BWithOAEPAndGCM(b *testing.B) { benchDecrypt("1B", "OAEPAndGCM", b) }
|
||||
func BenchmarkDecrypt64BWithOAEPAndGCM(b *testing.B) { benchDecrypt("64B", "OAEPAndGCM", b) }
|
||||
func BenchmarkDecrypt1KBWithOAEPAndGCM(b *testing.B) { benchDecrypt("1KB", "OAEPAndGCM", b) }
|
||||
func BenchmarkDecrypt64KBWithOAEPAndGCM(b *testing.B) { benchDecrypt("64KB", "OAEPAndGCM", b) }
|
||||
func BenchmarkDecrypt1MBWithOAEPAndGCM(b *testing.B) { benchDecrypt("1MB", "OAEPAndGCM", b) }
|
||||
func BenchmarkDecrypt64MBWithOAEPAndGCM(b *testing.B) { benchDecrypt("64MB", "OAEPAndGCM", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithPKCSAndGCM(b *testing.B) { benchDecrypt("1B", "PKCSAndGCM", b) }
|
||||
func BenchmarkDecrypt64BWithPKCSAndGCM(b *testing.B) { benchDecrypt("64B", "PKCSAndGCM", b) }
|
||||
func BenchmarkDecrypt1KBWithPKCSAndGCM(b *testing.B) { benchDecrypt("1KB", "PKCSAndGCM", b) }
|
||||
func BenchmarkDecrypt64KBWithPKCSAndGCM(b *testing.B) { benchDecrypt("64KB", "PKCSAndGCM", b) }
|
||||
func BenchmarkDecrypt1MBWithPKCSAndGCM(b *testing.B) { benchDecrypt("1MB", "PKCSAndGCM", b) }
|
||||
func BenchmarkDecrypt64MBWithPKCSAndGCM(b *testing.B) { benchDecrypt("64MB", "PKCSAndGCM", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithOAEPAndCBC(b *testing.B) { benchDecrypt("1B", "OAEPAndCBC", b) }
|
||||
func BenchmarkDecrypt64BWithOAEPAndCBC(b *testing.B) { benchDecrypt("64B", "OAEPAndCBC", b) }
|
||||
func BenchmarkDecrypt1KBWithOAEPAndCBC(b *testing.B) { benchDecrypt("1KB", "OAEPAndCBC", b) }
|
||||
func BenchmarkDecrypt64KBWithOAEPAndCBC(b *testing.B) { benchDecrypt("64KB", "OAEPAndCBC", b) }
|
||||
func BenchmarkDecrypt1MBWithOAEPAndCBC(b *testing.B) { benchDecrypt("1MB", "OAEPAndCBC", b) }
|
||||
func BenchmarkDecrypt64MBWithOAEPAndCBC(b *testing.B) { benchDecrypt("64MB", "OAEPAndCBC", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithPKCSAndCBC(b *testing.B) { benchDecrypt("1B", "PKCSAndCBC", b) }
|
||||
func BenchmarkDecrypt64BWithPKCSAndCBC(b *testing.B) { benchDecrypt("64B", "PKCSAndCBC", b) }
|
||||
func BenchmarkDecrypt1KBWithPKCSAndCBC(b *testing.B) { benchDecrypt("1KB", "PKCSAndCBC", b) }
|
||||
func BenchmarkDecrypt64KBWithPKCSAndCBC(b *testing.B) { benchDecrypt("64KB", "PKCSAndCBC", b) }
|
||||
func BenchmarkDecrypt1MBWithPKCSAndCBC(b *testing.B) { benchDecrypt("1MB", "PKCSAndCBC", b) }
|
||||
func BenchmarkDecrypt64MBWithPKCSAndCBC(b *testing.B) { benchDecrypt("64MB", "PKCSAndCBC", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithDirectGCM128(b *testing.B) { benchDecrypt("1B", "DirectGCM128", b) }
|
||||
func BenchmarkDecrypt64BWithDirectGCM128(b *testing.B) { benchDecrypt("64B", "DirectGCM128", b) }
|
||||
func BenchmarkDecrypt1KBWithDirectGCM128(b *testing.B) { benchDecrypt("1KB", "DirectGCM128", b) }
|
||||
func BenchmarkDecrypt64KBWithDirectGCM128(b *testing.B) { benchDecrypt("64KB", "DirectGCM128", b) }
|
||||
func BenchmarkDecrypt1MBWithDirectGCM128(b *testing.B) { benchDecrypt("1MB", "DirectGCM128", b) }
|
||||
func BenchmarkDecrypt64MBWithDirectGCM128(b *testing.B) { benchDecrypt("64MB", "DirectGCM128", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithDirectCBC128(b *testing.B) { benchDecrypt("1B", "DirectCBC128", b) }
|
||||
func BenchmarkDecrypt64BWithDirectCBC128(b *testing.B) { benchDecrypt("64B", "DirectCBC128", b) }
|
||||
func BenchmarkDecrypt1KBWithDirectCBC128(b *testing.B) { benchDecrypt("1KB", "DirectCBC128", b) }
|
||||
func BenchmarkDecrypt64KBWithDirectCBC128(b *testing.B) { benchDecrypt("64KB", "DirectCBC128", b) }
|
||||
func BenchmarkDecrypt1MBWithDirectCBC128(b *testing.B) { benchDecrypt("1MB", "DirectCBC128", b) }
|
||||
func BenchmarkDecrypt64MBWithDirectCBC128(b *testing.B) { benchDecrypt("64MB", "DirectCBC128", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithDirectGCM256(b *testing.B) { benchDecrypt("1B", "DirectGCM256", b) }
|
||||
func BenchmarkDecrypt64BWithDirectGCM256(b *testing.B) { benchDecrypt("64B", "DirectGCM256", b) }
|
||||
func BenchmarkDecrypt1KBWithDirectGCM256(b *testing.B) { benchDecrypt("1KB", "DirectGCM256", b) }
|
||||
func BenchmarkDecrypt64KBWithDirectGCM256(b *testing.B) { benchDecrypt("64KB", "DirectGCM256", b) }
|
||||
func BenchmarkDecrypt1MBWithDirectGCM256(b *testing.B) { benchDecrypt("1MB", "DirectGCM256", b) }
|
||||
func BenchmarkDecrypt64MBWithDirectGCM256(b *testing.B) { benchDecrypt("64MB", "DirectGCM256", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithDirectCBC256(b *testing.B) { benchDecrypt("1B", "DirectCBC256", b) }
|
||||
func BenchmarkDecrypt64BWithDirectCBC256(b *testing.B) { benchDecrypt("64B", "DirectCBC256", b) }
|
||||
func BenchmarkDecrypt1KBWithDirectCBC256(b *testing.B) { benchDecrypt("1KB", "DirectCBC256", b) }
|
||||
func BenchmarkDecrypt64KBWithDirectCBC256(b *testing.B) { benchDecrypt("64KB", "DirectCBC256", b) }
|
||||
func BenchmarkDecrypt1MBWithDirectCBC256(b *testing.B) { benchDecrypt("1MB", "DirectCBC256", b) }
|
||||
func BenchmarkDecrypt64MBWithDirectCBC256(b *testing.B) { benchDecrypt("64MB", "DirectCBC256", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1B", "AESKWAndGCM128", b) }
|
||||
func BenchmarkDecrypt64BWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64B", "AESKWAndGCM128", b) }
|
||||
func BenchmarkDecrypt1KBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1KB", "AESKWAndGCM128", b) }
|
||||
func BenchmarkDecrypt64KBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64KB", "AESKWAndGCM128", b) }
|
||||
func BenchmarkDecrypt1MBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1MB", "AESKWAndGCM128", b) }
|
||||
func BenchmarkDecrypt64MBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64MB", "AESKWAndGCM128", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1B", "AESKWAndCBC256", b) }
|
||||
func BenchmarkDecrypt64BWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64B", "AESKWAndCBC256", b) }
|
||||
func BenchmarkDecrypt1KBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1KB", "AESKWAndCBC256", b) }
|
||||
func BenchmarkDecrypt64KBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64KB", "AESKWAndCBC256", b) }
|
||||
func BenchmarkDecrypt1MBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1MB", "AESKWAndCBC256", b) }
|
||||
func BenchmarkDecrypt64MBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64MB", "AESKWAndCBC256", b) }
|
||||
|
||||
func BenchmarkDecrypt1BWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1B", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64BWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64B", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt1KBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1KB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64KBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64KB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt1MBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1MB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64MBWithECDHOnP256AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64MB", "ECDHOnP256AndGCM128", b)
|
||||
}
|
||||
|
||||
func BenchmarkDecrypt1BWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1B", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64BWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64B", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt1KBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1KB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64KBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64KB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt1MBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1MB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64MBWithECDHOnP384AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64MB", "ECDHOnP384AndGCM128", b)
|
||||
}
|
||||
|
||||
func BenchmarkDecrypt1BWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1B", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64BWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64B", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt1KBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1KB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64KBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64KB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt1MBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchDecrypt("1MB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
func BenchmarkDecrypt64MBWithECDHOnP521AndGCM128(b *testing.B) {
|
||||
benchDecrypt("64MB", "ECDHOnP521AndGCM128", b)
|
||||
}
|
||||
|
||||
func benchDecrypt(chunkKey, primKey string, b *testing.B) {
|
||||
chunk, ok := chunks[chunkKey]
|
||||
if !ok {
|
||||
b.Fatalf("unknown chunk size %s", chunkKey)
|
||||
}
|
||||
|
||||
enc, ok := encrypters[primKey]
|
||||
if !ok {
|
||||
b.Fatalf("unknown encrypter %s", primKey)
|
||||
}
|
||||
|
||||
dec, ok := decryptionKeys[primKey]
|
||||
if !ok {
|
||||
b.Fatalf("unknown decryption key %s", primKey)
|
||||
}
|
||||
|
||||
data, err := enc.Encrypt(chunk)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.SetBytes(int64(len(chunk)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
data.Decrypt(dec)
|
||||
}
|
||||
}
|
||||
|
||||
func mustEncrypter(keyAlg KeyAlgorithm, encAlg ContentEncryption, encryptionKey interface{}) Encrypter {
|
||||
enc, err := NewEncrypter(keyAlg, encAlg, encryptionKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return enc
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Dummy encrypter for use in examples
|
||||
var encrypter, _ = NewEncrypter(DIRECT, A128GCM, []byte{})
|
||||
|
||||
func Example_jWE() {
|
||||
// Generate a public/private key pair to use for this example. The library
|
||||
// also provides two utility functions (LoadPublicKey and LoadPrivateKey)
|
||||
// that can be used to load keys from PEM/DER-encoded data.
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Instantiate an encrypter using RSA-OAEP with AES128-GCM. An error would
|
||||
// indicate that the selected algorithm(s) are not currently supported.
|
||||
publicKey := &privateKey.PublicKey
|
||||
encrypter, err := NewEncrypter(RSA_OAEP, A128GCM, publicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Encrypt a sample plaintext. Calling the encrypter returns an encrypted
|
||||
// JWE object, which can then be serialized for output afterwards. An error
|
||||
// would indicate a problem in an underlying cryptographic primitive.
|
||||
var plaintext = []byte("Lorem ipsum dolor sit amet")
|
||||
object, err := encrypter.Encrypt(plaintext)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Serialize the encrypted object using the full serialization format.
|
||||
// Alternatively you can also use the compact format here by calling
|
||||
// object.CompactSerialize() instead.
|
||||
serialized := object.FullSerialize()
|
||||
|
||||
// Parse the serialized, encrypted JWE object. An error would indicate that
|
||||
// the given input did not represent a valid message.
|
||||
object, err = ParseEncrypted(serialized)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Now we can decrypt and get back our original plaintext. An error here
|
||||
// would indicate the the message failed to decrypt, e.g. because the auth
|
||||
// tag was broken or the message was tampered with.
|
||||
decrypted, err := object.Decrypt(privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf(string(decrypted))
|
||||
// output: Lorem ipsum dolor sit amet
|
||||
}
|
||||
|
||||
func Example_jWS() {
|
||||
// Generate a public/private key pair to use for this example. The library
|
||||
// also provides two utility functions (LoadPublicKey and LoadPrivateKey)
|
||||
// that can be used to load keys from PEM/DER-encoded data.
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Instantiate a signer using RSASSA-PSS (SHA512) with the given private key.
|
||||
signer, err := NewSigner(PS512, privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Sign a sample payload. Calling the signer returns a protected JWS object,
|
||||
// which can then be serialized for output afterwards. An error would
|
||||
// indicate a problem in an underlying cryptographic primitive.
|
||||
var payload = []byte("Lorem ipsum dolor sit amet")
|
||||
object, err := signer.Sign(payload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Serialize the encrypted object using the full serialization format.
|
||||
// Alternatively you can also use the compact format here by calling
|
||||
// object.CompactSerialize() instead.
|
||||
serialized := object.FullSerialize()
|
||||
|
||||
// Parse the serialized, protected JWS object. An error would indicate that
|
||||
// the given input did not represent a valid message.
|
||||
object, err = ParseSigned(serialized)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Now we can verify the signature on the payload. An error here would
|
||||
// indicate the the message failed to verify, e.g. because the signature was
|
||||
// broken or the message was tampered with.
|
||||
output, err := object.Verify(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf(string(output))
|
||||
// output: Lorem ipsum dolor sit amet
|
||||
}
|
||||
|
||||
func ExampleNewEncrypter_publicKey() {
|
||||
var publicKey *rsa.PublicKey
|
||||
|
||||
// Instantiate an encrypter using RSA-OAEP with AES128-GCM.
|
||||
NewEncrypter(RSA_OAEP, A128GCM, publicKey)
|
||||
|
||||
// Instantiate an encrypter using RSA-PKCS1v1.5 with AES128-CBC+HMAC.
|
||||
NewEncrypter(RSA1_5, A128CBC_HS256, publicKey)
|
||||
}
|
||||
|
||||
func ExampleNewEncrypter_symmetric() {
|
||||
var sharedKey []byte
|
||||
|
||||
// Instantiate an encrypter using AES128-GCM with AES-GCM key wrap.
|
||||
NewEncrypter(A128GCMKW, A128GCM, sharedKey)
|
||||
|
||||
// Instantiate an encrypter using AES256-GCM directly, w/o key wrapping.
|
||||
NewEncrypter(DIRECT, A256GCM, sharedKey)
|
||||
}
|
||||
|
||||
func ExampleNewSigner_publicKey() {
|
||||
var rsaPrivateKey *rsa.PrivateKey
|
||||
var ecdsaPrivateKey *ecdsa.PrivateKey
|
||||
|
||||
// Instantiate a signer using RSA-PKCS#1v1.5 with SHA-256.
|
||||
NewSigner(RS256, rsaPrivateKey)
|
||||
|
||||
// Instantiate a signer using ECDSA with SHA-384.
|
||||
NewSigner(ES384, ecdsaPrivateKey)
|
||||
}
|
||||
|
||||
func ExampleNewSigner_symmetric() {
|
||||
var sharedKey []byte
|
||||
|
||||
// Instantiate an signer using HMAC-SHA256.
|
||||
NewSigner(HS256, sharedKey)
|
||||
|
||||
// Instantiate an signer using HMAC-SHA512.
|
||||
NewSigner(HS512, sharedKey)
|
||||
}
|
||||
|
||||
func ExampleNewMultiEncrypter() {
|
||||
var publicKey *rsa.PublicKey
|
||||
var sharedKey []byte
|
||||
|
||||
// Instantiate an encrypter using AES-GCM.
|
||||
encrypter, err := NewMultiEncrypter(A128GCM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Add a recipient using a shared key with AES-GCM key wap
|
||||
err = encrypter.AddRecipient(A128GCMKW, sharedKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Add a recipient using an RSA public key with RSA-OAEP
|
||||
err = encrypter.AddRecipient(RSA_OAEP, publicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleNewMultiSigner() {
|
||||
var privateKey *rsa.PrivateKey
|
||||
var sharedKey []byte
|
||||
|
||||
// Instantiate a signer for multiple recipients.
|
||||
signer := NewMultiSigner()
|
||||
|
||||
// Add a recipient using a shared key with HMAC-SHA256
|
||||
err := signer.AddRecipient(HS256, sharedKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Add a recipient using an RSA private key with RSASSA-PSS with SHA384
|
||||
err = signer.AddRecipient(PS384, privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleEncrypter_encrypt() {
|
||||
// Encrypt a plaintext in order to get an encrypted JWE object.
|
||||
var plaintext = []byte("This is a secret message")
|
||||
|
||||
encrypter.Encrypt(plaintext)
|
||||
}
|
||||
|
||||
func ExampleEncrypter_encryptWithAuthData() {
|
||||
// Encrypt a plaintext in order to get an encrypted JWE object. Also attach
|
||||
// some additional authenticated data (AAD) to the object. Note that objects
|
||||
// with attached AAD can only be represented using full serialization.
|
||||
var plaintext = []byte("This is a secret message")
|
||||
var aad = []byte("This is authenticated, but public data")
|
||||
|
||||
encrypter.EncryptWithAuthData(plaintext, aad)
|
||||
}
|
||||
|
|
@ -132,6 +132,14 @@ func newBuffer(data []byte) *byteBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
func newFixedSizeBuffer(data []byte, length int) *byteBuffer {
|
||||
if len(data) > length {
|
||||
panic("square/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)")
|
||||
}
|
||||
pad := make([]byte, length-len(data))
|
||||
return newBuffer(append(pad, data...))
|
||||
}
|
||||
|
||||
func newBufferFromInt(num uint64) *byteBuffer {
|
||||
data := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(data, num)
|
||||
|
|
|
|||
173
Godeps/_workspace/src/github.com/letsencrypt/go-jose/encoding_test.go
generated
vendored
Normal file
173
Godeps/_workspace/src/github.com/letsencrypt/go-jose/encoding_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBase64URLEncode(t *testing.T) {
|
||||
// Test arrays with various sizes
|
||||
if base64URLEncode([]byte{}) != "" {
|
||||
t.Error("failed to encode empty array")
|
||||
}
|
||||
|
||||
if base64URLEncode([]byte{0}) != "AA" {
|
||||
t.Error("failed to encode [0x00]")
|
||||
}
|
||||
|
||||
if base64URLEncode([]byte{0, 1}) != "AAE" {
|
||||
t.Error("failed to encode [0x00, 0x01]")
|
||||
}
|
||||
|
||||
if base64URLEncode([]byte{0, 1, 2}) != "AAEC" {
|
||||
t.Error("failed to encode [0x00, 0x01, 0x02]")
|
||||
}
|
||||
|
||||
if base64URLEncode([]byte{0, 1, 2, 3}) != "AAECAw" {
|
||||
t.Error("failed to encode [0x00, 0x01, 0x02, 0x03]")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64URLDecode(t *testing.T) {
|
||||
// Test arrays with various sizes
|
||||
val, err := base64URLDecode("")
|
||||
if err != nil || !bytes.Equal(val, []byte{}) {
|
||||
t.Error("failed to decode empty array")
|
||||
}
|
||||
|
||||
val, err = base64URLDecode("AA")
|
||||
if err != nil || !bytes.Equal(val, []byte{0}) {
|
||||
t.Error("failed to decode [0x00]")
|
||||
}
|
||||
|
||||
val, err = base64URLDecode("AAE")
|
||||
if err != nil || !bytes.Equal(val, []byte{0, 1}) {
|
||||
t.Error("failed to decode [0x00, 0x01]")
|
||||
}
|
||||
|
||||
val, err = base64URLDecode("AAEC")
|
||||
if err != nil || !bytes.Equal(val, []byte{0, 1, 2}) {
|
||||
t.Error("failed to decode [0x00, 0x01, 0x02]")
|
||||
}
|
||||
|
||||
val, err = base64URLDecode("AAECAw")
|
||||
if err != nil || !bytes.Equal(val, []byte{0, 1, 2, 3}) {
|
||||
t.Error("failed to decode [0x00, 0x01, 0x02, 0x03]")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeflateRoundtrip(t *testing.T) {
|
||||
original := []byte("Lorem ipsum dolor sit amet")
|
||||
|
||||
compressed, err := deflate(original)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
output, err := inflate(compressed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if bytes.Compare(output, original) != 0 {
|
||||
t.Error("Input and output do not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidCompression(t *testing.T) {
|
||||
_, err := compress("XYZ", []byte{})
|
||||
if err == nil {
|
||||
t.Error("should not accept invalid algorithm")
|
||||
}
|
||||
|
||||
_, err = decompress("XYZ", []byte{})
|
||||
if err == nil {
|
||||
t.Error("should not accept invalid algorithm")
|
||||
}
|
||||
|
||||
_, err = decompress(DEFLATE, []byte{1, 2, 3, 4})
|
||||
if err == nil {
|
||||
t.Error("should not accept invalid data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBufferTrim(t *testing.T) {
|
||||
buf := newBufferFromInt(1)
|
||||
if !bytes.Equal(buf.data, []byte{1}) {
|
||||
t.Error("Byte buffer for integer '1' should contain [0x01]")
|
||||
}
|
||||
|
||||
buf = newBufferFromInt(65537)
|
||||
if !bytes.Equal(buf.data, []byte{1, 0, 1}) {
|
||||
t.Error("Byte buffer for integer '65537' should contain [0x01, 0x00, 0x01]")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFixedSizeBuffer(t *testing.T) {
|
||||
data0 := []byte{}
|
||||
data1 := []byte{1}
|
||||
data2 := []byte{1, 2}
|
||||
data3 := []byte{1, 2, 3}
|
||||
data4 := []byte{1, 2, 3, 4}
|
||||
|
||||
buf0 := newFixedSizeBuffer(data0, 4)
|
||||
buf1 := newFixedSizeBuffer(data1, 4)
|
||||
buf2 := newFixedSizeBuffer(data2, 4)
|
||||
buf3 := newFixedSizeBuffer(data3, 4)
|
||||
buf4 := newFixedSizeBuffer(data4, 4)
|
||||
|
||||
if !bytes.Equal(buf0.data, []byte{0, 0, 0, 0}) {
|
||||
t.Error("Invalid padded buffer for buf0")
|
||||
}
|
||||
if !bytes.Equal(buf1.data, []byte{0, 0, 0, 1}) {
|
||||
t.Error("Invalid padded buffer for buf1")
|
||||
}
|
||||
if !bytes.Equal(buf2.data, []byte{0, 0, 1, 2}) {
|
||||
t.Error("Invalid padded buffer for buf2")
|
||||
}
|
||||
if !bytes.Equal(buf3.data, []byte{0, 1, 2, 3}) {
|
||||
t.Error("Invalid padded buffer for buf3")
|
||||
}
|
||||
if !bytes.Equal(buf4.data, []byte{1, 2, 3, 4}) {
|
||||
t.Error("Invalid padded buffer for buf4")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerializeJSONRejectsNil(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil || !strings.Contains(r.(string), "nil pointer") {
|
||||
t.Error("serialize function should not accept nil pointer")
|
||||
}
|
||||
}()
|
||||
|
||||
mustSerializeJSON(nil)
|
||||
}
|
||||
|
||||
func TestFixedSizeBufferTooLarge(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
t.Error("should not be able to create fixed size buffer with oversized data")
|
||||
}
|
||||
}()
|
||||
|
||||
newFixedSizeBuffer(make([]byte, 2), 1)
|
||||
}
|
||||
|
|
@ -129,6 +129,12 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
|||
|
||||
obj.Header = obj.mergedHeaders(nil).sanitized()
|
||||
|
||||
// Check that there is not a nonce in the unprotected headers
|
||||
if (parsed.Unprotected != nil && parsed.Unprotected.Nonce != "") ||
|
||||
(parsed.Header != nil && parsed.Header.Nonce != "") {
|
||||
return nil, ErrUnprotectedNonce
|
||||
}
|
||||
|
||||
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
||||
err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
|
||||
if err != nil {
|
||||
|
|
@ -151,6 +157,11 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Check that there is not a nonce in the unprotected header
|
||||
if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.Nonce != "" {
|
||||
return nil, ErrUnprotectedNonce
|
||||
}
|
||||
|
||||
obj.recipients[r].header = parsed.Recipients[r].Header
|
||||
obj.recipients[r].encryptedKey = encryptedKey
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,537 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompactParseJWE(t *testing.T) {
|
||||
// Should parse
|
||||
msg := "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA"
|
||||
_, err := ParseEncrypted(msg)
|
||||
if err != nil {
|
||||
t.Error("Unable to parse valid message:", err)
|
||||
}
|
||||
|
||||
// Messages that should fail to parse
|
||||
failures := []string{
|
||||
// Too many parts
|
||||
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
|
||||
// Not enough parts
|
||||
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA",
|
||||
// Invalid encrypted key
|
||||
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.//////.dGVzdA.dGVzdA.dGVzdA",
|
||||
// Invalid IV
|
||||
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.//////.dGVzdA.dGVzdA",
|
||||
// Invalid ciphertext
|
||||
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.//////.dGVzdA",
|
||||
// Invalid tag
|
||||
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.//////",
|
||||
// Invalid header
|
||||
"W10.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
|
||||
// Invalid header
|
||||
"######.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
|
||||
// Missing alc/enc params
|
||||
"e30.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
|
||||
}
|
||||
|
||||
for _, msg := range failures {
|
||||
_, err = ParseEncrypted(msg)
|
||||
if err == nil {
|
||||
t.Error("Able to parse invalid message", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullParseJWE(t *testing.T) {
|
||||
// Messages that should succeed to parse
|
||||
successes := []string{
|
||||
// Flattened serialization, single recipient
|
||||
"{\"protected\":\"eyJhbGciOiJYWVoiLCJlbmMiOiJYWVoifQo\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
// Unflattened serialization, single recipient
|
||||
"{\"protected\":\"\",\"unprotected\":{\"enc\":\"XYZ\"},\"recipients\":[{\"header\":{\"alg\":\"XYZ\"},\"encrypted_key\":\"QUJD\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
}
|
||||
|
||||
for i := range successes {
|
||||
_, err := ParseEncrypted(successes[i])
|
||||
if err != nil {
|
||||
t.Error("Unble to parse valid message", err, successes[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Messages that should fail to parse
|
||||
failures := []string{
|
||||
// Empty
|
||||
"{}",
|
||||
// Invalid JSON
|
||||
"{XX",
|
||||
// Invalid protected header
|
||||
"{\"protected\":\"###\"}",
|
||||
// Invalid protected header
|
||||
"{\"protected\":\"e1gK\"}",
|
||||
// Invalid encrypted key
|
||||
"{\"protected\":\"e30\",\"encrypted_key\":\"###\"}",
|
||||
// Invalid IV
|
||||
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"###\"}",
|
||||
// Invalid ciphertext
|
||||
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"###\"}",
|
||||
// Invalid tag
|
||||
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"###\"}",
|
||||
// Invalid AAD
|
||||
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\",\"aad\":\"###\"}",
|
||||
// Missing alg/enc headers
|
||||
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
// Missing enc header
|
||||
"{\"protected\":\"eyJhbGciOiJYWVoifQ\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
// Missing alg header
|
||||
"{\"protected\":\"eyJlbmMiOiJYWVoifQ\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
// Unflattened serialization, single recipient, invalid encrypted_key
|
||||
"{\"protected\":\"\",\"recipients\":[{\"header\":{\"alg\":\"XYZ\", \"enc\":\"XYZ\"},\"encrypted_key\":\"###\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
// Unflattened serialization, single recipient, missing alg
|
||||
"{\"protected\":\"eyJhbGciOiJYWVoifQ\",\"recipients\":[{\"encrypted_key\":\"QUJD\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
|
||||
}
|
||||
|
||||
for i := range failures {
|
||||
_, err := ParseEncrypted(failures[i])
|
||||
if err == nil {
|
||||
t.Error("Able to parse invalid message", err, failures[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingInvalidHeaders(t *testing.T) {
|
||||
obj := &JsonWebEncryption{
|
||||
protected: &rawHeader{Enc: A128GCM},
|
||||
unprotected: &rawHeader{},
|
||||
recipients: []recipientInfo{
|
||||
recipientInfo{},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := obj.Decrypt(nil)
|
||||
if err != ErrUnsupportedKeyType {
|
||||
t.Error("should detect invalid key")
|
||||
}
|
||||
|
||||
obj.unprotected.Crit = []string{"1", "2"}
|
||||
|
||||
_, err = obj.Decrypt(nil)
|
||||
if err == nil {
|
||||
t.Error("should reject message with crit header")
|
||||
}
|
||||
|
||||
obj.unprotected.Crit = nil
|
||||
obj.protected = &rawHeader{Alg: string(RSA1_5)}
|
||||
|
||||
_, err = obj.Decrypt(rsaTestKey)
|
||||
if err == nil || err == ErrCryptoFailure {
|
||||
t.Error("should detect missing enc header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectUnprotectedJWENonce(t *testing.T) {
|
||||
// No need to test compact, since that's always protected
|
||||
|
||||
// Flattened JSON
|
||||
input := `{
|
||||
"header": {
|
||||
"alg": "XYZ", "enc": "XYZ",
|
||||
"nonce": "should-cause-an-error"
|
||||
},
|
||||
"encrypted_key": "does-not-matter",
|
||||
"aad": "does-not-matter",
|
||||
"iv": "does-not-matter",
|
||||
"ciphertext": "does-not-matter",
|
||||
"tag": "does-not-matter"
|
||||
}`
|
||||
_, err := ParseEncrypted(input)
|
||||
if err == nil {
|
||||
t.Error("JWE with an unprotected nonce parsed as valid.")
|
||||
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
|
||||
t.Errorf("Improper error for unprotected nonce: %v", err)
|
||||
}
|
||||
|
||||
input = `{
|
||||
"unprotected": {
|
||||
"alg": "XYZ", "enc": "XYZ",
|
||||
"nonce": "should-cause-an-error"
|
||||
},
|
||||
"encrypted_key": "does-not-matter",
|
||||
"aad": "does-not-matter",
|
||||
"iv": "does-not-matter",
|
||||
"ciphertext": "does-not-matter",
|
||||
"tag": "does-not-matter"
|
||||
}`
|
||||
_, err = ParseEncrypted(input)
|
||||
if err == nil {
|
||||
t.Error("JWE with an unprotected nonce parsed as valid.")
|
||||
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
|
||||
t.Errorf("Improper error for unprotected nonce: %v", err)
|
||||
}
|
||||
|
||||
// Full JSON
|
||||
input = `{
|
||||
"header": { "alg": "XYZ", "enc": "XYZ" },
|
||||
"aad": "does-not-matter",
|
||||
"iv": "does-not-matter",
|
||||
"ciphertext": "does-not-matter",
|
||||
"tag": "does-not-matter",
|
||||
"recipients": [{
|
||||
"header": { "nonce": "should-cause-an-error" },
|
||||
"encrypted_key": "does-not-matter"
|
||||
}]
|
||||
}`
|
||||
_, err = ParseEncrypted(input)
|
||||
if err == nil {
|
||||
t.Error("JWS with an unprotected nonce parsed as valid.")
|
||||
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
|
||||
t.Errorf("Improper error for unprotected nonce: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompactSerialize(t *testing.T) {
|
||||
// Compact serialization must fail if we have unprotected headers
|
||||
obj := &JsonWebEncryption{
|
||||
unprotected: &rawHeader{Alg: "XYZ"},
|
||||
}
|
||||
|
||||
_, err := obj.CompactSerialize()
|
||||
if err == nil {
|
||||
t.Error("Object with unprotected headers can't be compact serialized")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVectorsJWE(t *testing.T) {
|
||||
plaintext := []byte("The true sign of intelligence is not knowledge but imagination.")
|
||||
|
||||
publicKey := &rsa.PublicKey{
|
||||
N: fromBase64Int(`
|
||||
oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW
|
||||
cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S
|
||||
psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a
|
||||
sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS
|
||||
tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj
|
||||
YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw`),
|
||||
E: 65537,
|
||||
}
|
||||
|
||||
expectedCompact := stripWhitespace(`
|
||||
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.ROQCfge4JPm_
|
||||
yACxv1C1NSXmwNbL6kvmCuyxBRGpW57DvlwByjyjsb6g8m7wtLMqKEyhFCn
|
||||
tV7sjippEePIlKln6BvVnz5ZLXHNYQgmubuNq8MC0KTwcaGJ_C0z_T8j4PZ
|
||||
a1nfpbhSe-ePYaALrf_nIsSRKu7cWsrwOSlaRPecRnYeDd_ytAxEQWYEKFi
|
||||
Pszc70fP9geZOB_09y9jq0vaOF0jGmpIAmgk71lCcUpSdrhNokTKo5y8MH8
|
||||
3NcbIvmuZ51cjXQj1f0_AwM9RW3oCh2Hu0z0C5l4BujZVsDuGgMsGZsjUhS
|
||||
RZsAQSXHCAmlJ2NlnN60U7y4SPJhKv5tKYw.48V1_ALb6US04U3b.5eym8T
|
||||
W_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiS
|
||||
diwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`)
|
||||
|
||||
expectedFull := stripWhitespace(`
|
||||
{ "protected":"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ",
|
||||
"encrypted_key":
|
||||
"ROQCfge4JPm_yACxv1C1NSXmwNbL6kvmCuyxBRGpW57DvlwByjyjsb
|
||||
6g8m7wtLMqKEyhFCntV7sjippEePIlKln6BvVnz5ZLXHNYQgmubuNq
|
||||
8MC0KTwcaGJ_C0z_T8j4PZa1nfpbhSe-ePYaALrf_nIsSRKu7cWsrw
|
||||
OSlaRPecRnYeDd_ytAxEQWYEKFiPszc70fP9geZOB_09y9jq0vaOF0
|
||||
jGmpIAmgk71lCcUpSdrhNokTKo5y8MH83NcbIvmuZ51cjXQj1f0_Aw
|
||||
M9RW3oCh2Hu0z0C5l4BujZVsDuGgMsGZsjUhSRZsAQSXHCAmlJ2Nln
|
||||
N60U7y4SPJhKv5tKYw",
|
||||
"iv": "48V1_ALb6US04U3b",
|
||||
"ciphertext":
|
||||
"5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFS
|
||||
hS8iB7j6jiSdiwkIr3ajwQzaBtQD_A",
|
||||
"tag":"XFBoMYUZodetZdvTiFvSkQ" }`)
|
||||
|
||||
// Mock random reader
|
||||
randReader = bytes.NewReader([]byte{
|
||||
// Encryption key
|
||||
177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154,
|
||||
212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122,
|
||||
234, 64, 252,
|
||||
// Randomness for RSA-OAEP
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// Initialization vector
|
||||
227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219})
|
||||
defer resetRandReader()
|
||||
|
||||
// Encrypt with a dummy key
|
||||
encrypter, err := NewEncrypter(RSA_OAEP, A256GCM, publicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
object, err := encrypter.Encrypt(plaintext)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
serialized, err := object.CompactSerialize()
|
||||
if serialized != expectedCompact {
|
||||
t.Error("Compact serialization is not what we expected", serialized, expectedCompact)
|
||||
}
|
||||
|
||||
serialized = object.FullSerialize()
|
||||
if serialized != expectedFull {
|
||||
t.Error("Full serialization is not what we expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVectorsJWECorrupt(t *testing.T) {
|
||||
priv := &rsa.PrivateKey{
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: fromHexInt(`
|
||||
a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8
|
||||
ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0c
|
||||
bc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bd
|
||||
bf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93
|
||||
ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb`),
|
||||
E: 65537,
|
||||
},
|
||||
D: fromHexInt(`
|
||||
53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf1195
|
||||
17ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d
|
||||
4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d6
|
||||
5a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb
|
||||
04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1`),
|
||||
Primes: []*big.Int{
|
||||
fromHexInt(`
|
||||
d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262
|
||||
864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c
|
||||
2f26a471dcad212eac7ca39d`),
|
||||
fromHexInt(`
|
||||
cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb3
|
||||
3d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af
|
||||
72bfe9a030e860b0288b5d77`),
|
||||
},
|
||||
}
|
||||
|
||||
corruptCiphertext := stripWhitespace(`
|
||||
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.NFl09dehy
|
||||
IR2Oh5iSsvEa82Ps7DLjRHeo0RnuTuSR45OsaIP6U8yu7vLlWaZKSZMy
|
||||
B2qRBSujf-5XIRoNhtyIyjk81eJRXGa_Bxaor1XBCMyyhGchW2H2P71f
|
||||
PhDO6ufSC7kV4bNqgHR-4ziS7KXwzN83_5kogXqxUpymUoJDNc.tk-GT
|
||||
W_VVhiTIKFF.D_BE6ImZUl9F.52a-zFnRb3YQwIC7UrhVyQ`)
|
||||
|
||||
corruptAuthtag := stripWhitespace(`
|
||||
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.NFl09dehy
|
||||
IR2Oh5iSsvEa82Ps7DLjRHeo0RnuTuSR45OsaIP6U8yu7vLlWaZKSZMy
|
||||
B2qRBSujf-5XIRoNhtyIyjk81eJRXGa_Bxaor1XBCMyyhGchW2H2P71f
|
||||
PhDO6ufSC7kV4bNqgHR-4ziS7KNwzN83_5kogXqxUpymUoJDNc.tk-GT
|
||||
W_VVhiTIKFF.D_BE6ImZUl9F.52a-zFnRb3YQwiC7UrhVyQ`)
|
||||
|
||||
msg, _ := ParseEncrypted(corruptCiphertext)
|
||||
_, err := msg.Decrypt(priv)
|
||||
if err != ErrCryptoFailure {
|
||||
t.Error("should detect corrupt ciphertext")
|
||||
}
|
||||
|
||||
msg, _ = ParseEncrypted(corruptAuthtag)
|
||||
_, err = msg.Decrypt(priv)
|
||||
if err != ErrCryptoFailure {
|
||||
t.Error("should detect corrupt auth tag")
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors generated with nimbus-jose-jwt
|
||||
func TestSampleNimbusJWEMessagesRSA(t *testing.T) {
|
||||
rsaPrivateKey, err := LoadPrivateKey(fromBase64Bytes(`
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCNRCEmf5PlbXKuT4uwnb
|
||||
wGKvFrtpi+bDYxOZxxqxdVkZM/bYATAnD1fg9pNvLMKeF+MWJ9kPIMmDgOh9RdnRdLvQGb
|
||||
BzhLmxwhhcua2QYiHEZizXmiaXvNP12bzEBhebdX7ObW8izMVW0p0lqHPNzkK3K75B0Sxo
|
||||
FMVKkZ7KtBHgepBT5yPhPPcNe5lXQeTne5bo3I60DRcN9jTBgMJOXdq0I9o4y6ZmoXdNTm
|
||||
0EyLzn9/EYiHqBxtKFh791EHR7wYgyi/t+nOKr4sO74NbEByP0mHDil+mPvZSzFW4l7fPx
|
||||
OclRZvpRIKIub2TroZA9s2WsshGf79eqqXYbBB9NNRAgMBAAECggEAIExbZ/nzTplfhwsY
|
||||
3SCzRJW87OuqsJ79JPQPGM4NX7sQ94eJqM7+FKLl0yCFErjgnYGdCyiArvB+oJPdsimgke
|
||||
h83X0hGeg03lVA3/6OsG3WifCAxulnLN44AM8KST8S9D9t5+cm5vEBLHazzAfWWTS13s+g
|
||||
9hH8rf8NSqgZ36EutjKlvLdHx1mWcKX7SREFVHT8FWPAbdhTLEHUjoWHrfSektnczaSHnt
|
||||
q8fFJy6Ld13QkF1ZJRUhtA24XrD+qLTc+M36IuedjeZaLHFB+KyhYR3YvXEtrbCug7dCRd
|
||||
uG6uTlDCSaSy7xHeTPolWtWo9F202jal54otxiAJFGUHgQKBgQDRAT0s6YQZUfwE0wluXV
|
||||
k0JdhDdCo8sC1aMmKlRKWUkBAqrDl7BI3MF56VOr4ybr90buuscshFf9TtrtBOjHSGcfDI
|
||||
tSKfhhkW5ewQKB0YqyHzoD6UKT0/XAshFY3esc3uCxuJ/6vOiXV0og9o7eFvr51O0TfDFh
|
||||
mcTvW4wirKlQKBgQCtB7UAu8I9Nn8czkd6oXLDRyTWYviuiqFmxR+PM9klgZtsumkeSxO1
|
||||
lkfFoj9+G8nFaqYEBA9sPeNtJVTSROCvj/iQtoqpV2NiI/wWeVszpBwsswx2mlks4LJa8a
|
||||
Yz9xrsfNoroKYVppefc/MCoSx4M+99RSm3FSpLGZQHAUGyzQKBgQDMQmq4JuuMF1y2lk0E
|
||||
SESyuz21BqV0tDVOjilsHT+5hmXWXoS6nkO6L2czrrpM7YE82F6JJZBmo7zEIXHBInGLJ3
|
||||
XLoYLZ5qNEhqYDUEDHaBCBWZ1vDTKnZlwWFEuXVavNNZvPbUhKTHq25t8qjDki/r09Vykp
|
||||
BsM2yNBKpbBOVQKBgCJyUVd3CaFUExQyAMrqD0XPCQdhJq7gzGcAQVsp8EXmOoH3zmuIeM
|
||||
ECzQEMXuWFNLMHm0tbX5Kl83vMHcnKioyI9ewhWxOBYTitf0ceG8j5F97SOl32NmCXzwoJ
|
||||
55Oa0xJXfLuIvOe8hZzp4WwZmBfKBxiCR166aPQQgIawelrVAoGAEJsHomfCI4epxH4oMw
|
||||
qYJMCGy95zloB+2+c86BZCOJAGwnfzbtc2eutWZw61/9sSO8sQCfzA8oX+5HwAgnFVzwW4
|
||||
lNMZohppYcpwN9EyjkPaCXuALC7p5rF2o63wY7JLvnjS2aYZliknh2yW6X6fSB0PK0Cpvd
|
||||
lAIyRw6Kud0zI=`))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rsaSampleMessages := []string{
|
||||
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBMV81In0.EW0KOhHeoAxTBnLjYhh2T6HjwI-srNs6RpcSdZvE-GJ5iww3EYWBCmeGGj1UVz6OcBfwW3wllZ6GPOHU-hxVQH5KYpVOjkmrFIYU6-8BHhxBP_PjSJEBCZzjOgsCm9Th4-zmlO7UWTdK_UtwE7nk4X-kkmEy-aZBCShA8nFe2MVvqD5F7nvEWNFBOHh8ae_juo-kvycoIzvxLV9g1B0Zn8K9FAlu8YF1KiL5NFekn76f3jvAwlExuRbFPUx4gJN6CeBDK_D57ABsY2aBVDSiQceuYZxvCIAajqSS6dMT382FNJzAiQhToOpo_1w5FnnBjzJLLEKDk_I-Eo2YCWxxsQ.5mCMuxJqLRuPXGAr.Ghe4INeBhP3MDWGvyNko7qanKdZIzKjfeiU.ja3UlVWJXKNFJ-rZsJWycw",
|
||||
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBMV81In0.JsJeYoP0St1bRYNUaAmA34DAA27usE7RNuC2grGikBRmh1xrwUOpnEIXXpwr7fjVmNi52zzWkNHC8JkkRTrLcCh2VXvnOnarpH8DCr9qM6440bSrahzbxIvDds8z8q0wT1W4kjVnq1mGwGxg8RQNBWTV6Sp2FLQkZyjzt_aXsgYzr3zEmLZxB-d41lBS81Mguk_hdFJIg_WO4ao54lozvxkCn_uMiIZ8eLb8qHy0h-N21tiHGCaiC2vV8KXomwoqbJ0SXrEH4r9_R2J844H80TBZdbvNBd8whvoQNHvOX659LNs9EQ9xxvHU2kqGZekXBu7sDXXTjctMkMITobGSzw.1v5govaDvanP3LGp.llwYNBDrD7MwVLaFHesljlratfmndWs4XPQ.ZGT1zk9_yIKi2GzW6CuAyA",
|
||||
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBMV81In0.fBv3fA3TMS3ML8vlsCuvwdsKvB0ym8R30jJrlOiqkWKk7WVUkjDInFzr1zw3Owla6c5BqOJNoACXt4IWbkLbkoWV3tweXlWwpafuaWPkjLOUH_K31rS2fCX5x-MTj8_hScquVQXpbz3vk2EfulRmGXZc_8JU2NqQCAsYy3a28houqP3rDe5jEAvZS2SOFvJkKW--f5S-z39t1D7fNz1N8Btd9SmXWQzjbul5YNxI9ctqxhJpkKYpxOLlvrzdA6YdJjOlDx3n6S-HnSZGM6kQd_xKtAf8l1EGwhQmhbXhMhjVxMvGwE5BX7PAb8Ccde5bzOCJx-PVbVetuLb169ZYqQ._jiZbOPRR82FEWMZ.88j68LI-K2KT6FMBEdlz6amG5nvaJU8a-90.EnEbUTJsWNqJYKzfO0x4Yw",
|
||||
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBMV81In0.bN6FN0qmGxhkESiVukrCaDVG3woL0xE-0bHN_Mu0WZXTQWbzzT-7jOvaN1xhGK8nzi8qpCSRgE5onONNB9i8OnJm3MMIxF7bUUEAXO9SUAFn2v--wNc4drPc5OjIu0RiJrDVDkkGjNrBDIuBaEQcke7A0v91PH58dXE7o4TLPzC8UJmRtXWhUSwjXVF3-UmYRMht2rjHJlvRbtm6Tu2LMBIopRL0zj6tlPP4Dm7I7sz9OEB3VahYAhpXnFR7D_f8RjLSXQmBvB1FiI5l_vMz2NFt2hYUmQF3EJMLIEdHvvPp3iHDGiXC1obJrDID_CCf3qs9UY7DMYL622KLvP2NIg.qb72oxECzxd_aNuHVR0aNg.Gwet9Ms8hB8rKEb0h4RGdFNRq97Qs2LQaJM0HWrCqoI.03ljVThOFvgXzMmQJ79VjQ",
|
||||
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBMV81In0.ZbEOP6rqdiIP4g7Nl1PL5gwhgDwv9RinyiUQxZXPOmD7kwEZrZ093dJnhqI9kEd3QGFlHDpB7HgNz53d27z2zmEj1-27v6miizq6tH4sN2MoeZLwSyk16O1_n3bVdDmROawsTYYFJfHsuLwyVJxPd37duIYnbUCFO9J8lLIv-2VI50KJ1t47YfE4P-Wt9jVzxP2CVUQaJwTlcwfiDLJTagYmfyrDjf525WlQFlgfJGqsJKp8BX9gmKvAo-1iCBAM8VpEjS0u0_hW9VSye36yh8BthVV-VJkhJ-0tMpto3bbBmj7M25Xf4gbTrrVU7Nz6wb18YZuhHZWmj2Y2nHV6Jg.AjnS44blTrIIfFlqVw0_Mg.muCRgaEXNKKpW8rMfW7jf7Zpn3VwSYDz-JTRg16jZxY.qjc9OGlMaaWKDWQSIwVpR4K556Pp6SF9",
|
||||
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBMV81In0.c7_F1lMlRHQQE3WbKmtHBYTosdZrG9hPfs-F9gNQYet61zKG8NXVkSy0Zf2UFHt0vhcO8hP2qrqOFsy7vmRj20xnGHQ2EE29HH6hwX5bx1Jj3uE5WT9Gvh0OewpvF9VubbwWTIObBpdEG7XdJsMAQlIxtXUmQYAtLTWcy2ZJipyJtVlWQLaPuE8BKfZH-XAsp2CpQNiRPI8Ftza3EAspiyRfVQbjKt7nF8nuZ2sESjt7Y50q4CSiiCuGT28T3diMN0_rWrH-I-xx7OQvJlrQaNGglGtu3jKUcrJDcvxW2e1OxriaTeuQ848ayuRvGUNeSv6WoVYmkiK1x_gNwUAAbw.7XtSqHJA7kjt6JrfxJMwiA.Yvi4qukAbdT-k-Fd2s4G8xzL4VFxaFC0ZIzgFDAI6n0.JSWPJ-HjOE3SK9Lm0yHclmjS7Z1ahtQga9FHGCWVRcc",
|
||||
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.SYVxJbCnJ_tcR13LJpaqHQj-nGNkMxre4A1FmnUdxnvzeJwuvyrLiUdRsZR1IkP4fqLtDON2mumx39QeJQf0WIObPBYlIxycRLkwxDHRVlyTmPvdZHAxN26jPrk09wa5SgK1UF1W1VSQIPm-Tek8jNAmarF1Yxzxl-t54wZFlQiHP4TuaczugO5f-J4nlWenfla2mU1snDgdUMlEZGOAQ_gTEtwSgd1MqXmK_7LZBkoDqqoCujMZhziafJPXPDaUUqBLW3hHkkDA7GpVec3XcTtNUWQJqOpMyQhqo1KQMc8jg3fuirILp-hjvvNVtBnCRBvbrKUCPzu2_yH3HM_agA.2VsdijtonAxShNIW.QzzB3P9CxYP3foNKN0Ma1Z9tMwijAlkWo08.ZdQkIPDY_M-hxqi5fD4NGw",
|
||||
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.Z2oTJXXib1u-S38Vn3DRKE3JnhnwgUa92UhsefzY2Wpdn0dmxMfYt9iRoJGFfSAcA97MOfjyvXVRCKWXGrG5AZCMAXEqU8SNQwKPRjlcqojcVzQyMucXI0ikLC4mUgeRlfKTwsBicq6JZZylzRoLGGSNJQbni3_BLsf7H3Qor0BYg0FPCLG9Z2OVvrFzvjTLmZtV6gFlVrMHBxJub_aUet9gAkxiu1Wx_Kx46TlLX2tkumXIpTGlzX6pef6jLeZ5EIg_K-Uz4tkWgWQIEkLD7qmTyk5pAGmzukHa_08jIh5-U-Sd8XGZdx4J1pVPJ5CPg0qDJGZ_cfgkgpWbP_wB6A.4qgKfokK1EwYxz20._Md82bv_KH2Vru0Ue2Eb6oAqHP2xBBP5jF8.WFRojvQpD5VmZlOr_dN0rQ",
|
||||
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.JzCUgJcBJmBgByp4PBAABUfhezPvndxBIVzaoZ96DAS0HPni0OjMbsOGsz6JwNsiTr1gSn_S6R1WpZM8GJc9R2z0EKKVP67TR62ZSG0MEWyLpHmG_4ug0fAp1HWWMa9bT4ApSaOLgwlpVAb_-BPZZgIu6c8cREuMon6UBHDqW1euTBbzk8zix3-FTZ6p5b_3soDL1wXfRiRBEsxxUGMnpryx1OFb8Od0JdyGF0GgfLt6OoaujDJpo-XtLRawu1Xlg6GqRs0NQwSHZ5jXgQ6-zgCufXonAmYTiIyBXY2no9XmECTexjwrS_05nA7H-UyIZEBOCp3Yhz2zxrt5j_0pvQ.SJR-ghhaUKP4zXtZ.muiuzLfZA0y0BDNsroGTw2r2-l73SLf9lK8.XFMH1oHr1G6ByP3dWSUUPA",
|
||||
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAifQ.U946MVfIm4Dpk_86HrnIA-QXyiUu0LZ67PL93CMLmEtJemMNDqmRd9fXyenCIhAC7jPIV1aaqW7gS194xyrrnUpBoJBdbegiPqOfquy493Iq_GQ8OXnFxFibPNQ6rU0l8BwIfh28ei_VIF2jqN6bhxFURCVW7fG6n6zkCCuEyc7IcxWafSHjH2FNttREuVj-jS-4LYDZsFzSKbpqoYF6mHt8H3btNEZDTSmy_6v0fV1foNtUKNfWopCp-iE4hNh4EzJfDuU8eXLhDb03aoOockrUiUCh-E0tQx9su4rOv-mDEOHHAQK7swm5etxoa7__9PC3Hg97_p4GM9gC9ykNgw.pnXwvoSPi0kMQP54of-HGg.RPJt1CMWs1nyotx1fOIfZ8760mYQ69HlyDp3XmdVsZ8.Yxw2iPVWaBROFE_FGbvodA",
|
||||
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBLU9BRVAifQ.eKEOIJUJpXmO_ghH_nGCJmoEspqKyiy3D5l0P8lKutlo8AuYHPQlgOsaFYnDkypyUVWd9zi-JaQuCeo7dzoBiS1L71nAZo-SUoN0anQBkVuyuRjr-deJMhPPfq1H86tTk-4rKzPr1Ivd2RGXMtWsrUpNGk81r1v8DdMntLE7UxZQqT34ONuZg1IXnD_U6di7k07unI29zuU1ySeUr6w1YPw5aUDErMlpZcEJWrgOEYWaS2nuC8sWGlPGYEjqkACMFGn-y40UoS_JatNZO6gHK3SKZnXD7vN5NAaMo_mFNbh50e1t_zO8DaUdLtXPOBLcx_ULoteNd9H8HyDGWqwAPw.0xmtzJfeVMoIT1Cp68QrXA.841l1aA4c3uvSYfw6l180gn5JZQjL53WQ5fr8ejtvoI.lojzeWql_3gDq-AoaIbl_aGQRH_54w_f",
|
||||
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBLU9BRVAifQ.D0QkvIXR1TL7dIHWuPNMybmmD8UPyQd1bRKjRDNbA2HmKGpamCtcJmpNB_EetNFe-LDmhe44BYI_XN2wIBbYURKgDK_WG9BH0LQw_nCVqQ-sKqjtj3yQeytXhLHYTDmiF0TO-uW-RFR7GbPAdARBfuf4zj82r_wDD9sD5WSCGx89iPfozDOYQ_OLwdL2WD99VvDyfwS3ZhxA-9IMSYv5pwqPkxj4C0JdjCqrN0YNrZn_1ORgjtsVmcWXsmusObTozUGA7n5GeVepfZdU1vrMulAwdRYqOYtlqKaOpFowe9xFN3ncBG7wb4f9pmzbS_Dgt-1_Ii_4SEB9GQ4NiuBZ0w.N4AZeCxMGUv52A0UVJsaZw.5eHOGbZdtahnp3l_PDY-YojYib4ft4SRmdsQ2kggrTs.WsmGH8ZDv4ctBFs7qsQvw2obe4dVToRcAQaZ3PYL34E",
|
||||
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.fDTxO_ZzZ3Jdrdw-bxvg7u-xWB2q1tp3kI5zH6JfhLUm4h6rt9qDA_wZlRym8-GzEtkUjkTtQGs6HgQx_qlyy8ylCakY5GHsNhCG4m0UNhRiNfcasAs03JSXfON9-tfTJimWD9n4k5OHHhvcrsCW1G3jYeLsK9WHCGRIhNz5ULbo8HBrCTbmZ6bOEQ9mqhdssLpdV24HDpebotf3bgPJqoaTfWU6Uy7tLmPiNuuNRLQ-iTpLyNMTVvGqqZhpcV3lAEN5l77QabI5xLJYucvYjrXQhAEZ7YXO8oRYhGkdG2XXIRcwr87rBeRH-47HAyhZgF_PBPBhhrJNS9UNMqdfBw.FvU4_s7Md6vxnXWd.fw29Q4_gHt4f026DPPV-CNebQ8plJ6IVLX8._apBZrw7WsT8HOmxgCrTwA",
|
||||
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.bYuorK-rHMbO4c2CRWtvyOEaM1EN-o-wLRZ0wFWRX9mCXQ-iTNarZn7ksYM1XnGmZ4u3CSowX1Hpca9Rg72_VJCmKapqCT7r3YfasN4_oeLwuSKI_gT-uVOznod97tn3Gf_EDv0y1V4H0k9BEIFGbajAcG1znTD_ODY3j2KZJxisfrsBoslc6N-HI0kKZMC2hSGuHOcOf8HN1sTE-BLqZCtoj-zxQECJK8Wh14Ih4jzzdmmiu_qmSR780K6su-4PRt3j8uY7oCiLBfwpCsCmhJgp8rKd91zoedZmamfvX38mJIfE52j4fG6HmIYw9Ov814fk9OffV6tzixjcg54Q2g.yeVJz4aSh2s-GUr9.TBzzWP5llEiDdugpP2SmPf2U4MEGG9EoPWk.g25UoWpsBaOd45J__FX7mA",
|
||||
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.h9tFtmh762JuffBxlSQbJujCyI4Zs9yc3IOb1yR8g65W4ZHosIvzVGHWbShj4EY9MNrz-RbKtHfqQGGzDeo3Xb4-HcQ2ZDHyWoUg7VfA8JafJ5zIKL1npz8eUExOVMLsAaRfHg8qNfczodg3egoSmX5Q-nrx4DeidDSXYZaZjV0C72stLTPcuQ7XPV7z1tvERAkqpvcsRmJn_PiRNxIbAgoyHMJ4Gijuzt1bWZwezlxYmw0TEuwCTVC2fl9NJTZyxOntS1Lcm-WQGlPkVYeVgYTOQXLlp7tF9t-aAvYpth2oWGT6Y-hbPrjx_19WaKD0XyWCR46V32DlXEVDP3Xl2A.NUgfnzQyEaJjzt9r.k2To43B2YVWMeR-w3n4Pr2b5wYq2o87giHk.X8_QYCg0IGnn1pJqe8p_KA",
|
||||
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.EDq6cNP6Yp1sds5HZ4CkXYp7bs9plIYVZScKvuyxUy0H1VyBC_YWg0HvndPNb-vwh1LA6KMxRazlOwJ9iPR9YzHnYmGgPM3Je_ZzBfiPlRfq6hQBpGnNaypBI1XZ2tyFBhulsVLqyJe2SmM2Ud00kasOdMYgcN8FNFzq7IOE7E0FUQkIwLdUL1nrzepiYDp-5bGkxWRcL02cYfdqdm00G4m0GkUxAmdxa3oPNxZlt2NeBI_UVWQSgJE-DJVJQkDcyA0id27TV2RCDnmujYauNT_wYlyb0bFDx3pYzzNXfAXd4wHZxt75QaLZ5APJ0EVfiXJ0qki6kT-GRVmOimUbQA.vTULZL7LvS0WD8kR8ZUtLg.mb2f0StEmmkuuvsyz8UplMvF58FtZzlu8eEwzvPUvN0.hbhveEN40V-pgG2hSVgyKg",
|
||||
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.DuYk92p7u-YIN-JKn-XThmlVcnhU9x5TieQ2uhsLQVNlo0iWC9JJPP6bT6aI6u_1BIS3yE8_tSGGL7eM-zyEk6LuTqSWFRaZcZC06d0MnS9eYZcw1T2D17fL-ki-NtCaTahJD7jE2s0HevRVW49YtL-_V8whnO_EyVjvXIAQlPYqhH_o-0Nzcpng9ggdAnuF2rY1_6iRPYFJ3BLQvG1oWhyJ9s6SBttlOa0i6mmFCVLHx6sRpdGAB3lbCL3wfmHq4tpIv77gfoYUNP0SNff-zNmBXF_wp3dCntLZFTjbfMpGyHlruF_uoaLqwdjYpUGNUFVUoeSiMnSbMKm9NxiDgQ.6Mdgcqz7bMU1UeoAwFC8pg.W36QWOlBaJezakUX5FMZzbAgeAu_R14AYKZCQmuhguw.5OeyIJ03olxmJft8uBmjuOFQPWNZMYLI",
|
||||
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.ECulJArWFsPL2FlpCN0W8E7IseSjJg1cZqE3wz5jk9gvwgNForAUEv5KYZqhNI-p5IxkGV0f8K6Y2X8pWzbLwiPIjZe8_dVqHYJoINxqCSgWLBhz0V36qL9Nc_xARTBk4-ZteIu75NoXVeos9gNvFnkOCj4tm-jGo8z8EFO9XfODgjhiR4xv8VqUtvrkjo9GQConaga5zpV-J4JQlXbdqbDjnuwacnJAxYpFyuemqcgqsl6BnFX3tovGkmSUPqcvF1A6tiHqr-TEmcgVqo5C3xswknRBKTQRM00iAmJ92WlVdkoOCx6E6O7cVHFawZ14BLzWzm66Crb4tv0ucYvk_Q.mxolwUaoj5S5kHCfph0w8g.nFpgYdnYg3blHCCEi2XXQGkkKQBXs2OkZaH11m3PRvk.k8BAVT4EcyrUFVIKr-KOSPbF89xyL0Vri2rFTu2iIWM",
|
||||
}
|
||||
|
||||
for _, msg := range rsaSampleMessages {
|
||||
obj, err := ParseEncrypted(msg)
|
||||
if err != nil {
|
||||
t.Error("unable to parse message", msg, err)
|
||||
continue
|
||||
}
|
||||
plaintext, err := obj.Decrypt(rsaPrivateKey)
|
||||
if err != nil {
|
||||
t.Error("unable to decrypt message", msg, err)
|
||||
continue
|
||||
}
|
||||
if string(plaintext) != "Lorem ipsum dolor sit amet" {
|
||||
t.Error("plaintext is not what we expected for msg", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors generated with nimbus-jose-jwt
|
||||
func TestSampleNimbusJWEMessagesAESKW(t *testing.T) {
|
||||
aesTestKeys := [][]byte{
|
||||
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D"),
|
||||
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D95EC9CDC2D82233C"),
|
||||
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D95EC9CDC2D82233C333C35BA29044E90"),
|
||||
}
|
||||
|
||||
aesSampleMessages := [][]string{
|
||||
[]string{
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoib2ZMd2Q5NGloVWFRckJ0T1pQUDdjUSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiV2Z3TnN5cjEwWUFjY2p2diJ9.9x3RxdqIS6P9xjh93Eu1bQ.6fs3_fSGt2jull_5.YDlzr6sWACkFg_GU5MEc-ZEWxNLwI_JMKe_jFA.f-pq-V7rlSSg_q2e1gDygw",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoic2RneXB1ckFjTEFzTmZJU0lkZUNpUSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoieVFMR0dCdDJFZ0c1THdyViJ9.arslKo4aKlh6f4s0z1_-U-8JbmhAoZHN.Xw2Q-GX98YXwuc4i.halTEWMWAYZbv-qOD52G6bte4x6sxlh1_VpGEA.Z1spn016v58cW6Q2o0Qxag",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoicTNzejF5VUlhbVBDYXJfZ05kSVJqQSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiM0ZRM0FsLWJWdWhmcEIyQyJ9.dhVipWbzIdsINttuZM4hnjpHvwEHf0VsVrOp4GAg01g.dk7dUyt1Qj13Pipw.5Tt70ONATF0BZAS8dBkYmCV7AQUrfb8qmKNLmw.A6ton9MQjZg0b3C0QcW-hg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiUHNpTGphZnJZNE16UlRmNlBPLTZfdyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiSUFPbnd2ODR5YXFEaUxtbSJ9.swf92_LyCvjsvkynHTuMNXRl_MX2keU-fMDWIMezHG4.LOp9SVIXzs4yTnOtMyXZYQ.HUlXrzqJ1qXYl3vUA-ydezCg77WvJNtKdmZ3FPABoZw.8UYl1LOofQLAxHHvWqoTbg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiWGRndHQ5dUVEMVlVeU1rVHl6M3lqZyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiWF90V2RhSmh6X3J1SHJvQSJ9.JQ3dS1JSgzIFi5M9ig63FoFU1nHBTmPwXY_ovNE2m1JOSUvHtalmihIuraPDloCf.e920JVryUIWt7zJJQM-www.8DUrl4LmsxIEhRr9RLTHG9tBTOcwXqEbQHAJd_qMHzE.wHinoqGUhL4O7lx125kponpwNtlp8VGJ",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoicGgyaTdoY0FWNlh3ZkQta1RHYlVXdyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiaG41Smk4Wm1rUmRrSUxWVSJ9._bQlJXl22dhsBgYPhkxUyinBNi871teGWbviOueWj2PqG9OPxIc9SDS8a27YLSVDMircd5Q1Df28--vcXIABQA.DssmhrAg6w_f2VDaPpxTbQ.OGclEmqrxwvZqAfn7EgXlIfXgr0wiGvEbZz3zADnqJs.YZeP0uKVEiDl8VyC-s20YN-RbdyGNsbdtoGDP3eMof8",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTEyOEtXIn0.TEMcXEoY8WyqGjYs5GZgS-M_Niwu6wDY.i-26KtTt51Td6Iwd.wvhkagvPsLj3QxhPBbfH_th8OqxisUtme2UadQ.vlfvBPv3bw2Zk2H60JVNLQ",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTEyOEtXIn0.gPaR6mgQ9TUx05V6DRfgTQeZxl0ZSzBa5uQd-qw6yLs.MojplOD77FkMooS-.2yuD7dKR_C3sFbhgwiBccKKOF8DrSvNiwX7wPQ.qDKUbSvMnJv0qifjpWC14g",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTEyOEtXIn0.Fg-dgSkUW1KEaL5YDPoWHNL8fpX1WxWVLA9OOWsjIFhQVDKyUZI7BQ.mjRBpyJTZf7H-quf.YlNHezMadtaSKp23G-ozmYhHOeHwuJnvWGTtGg.YagnR7awBItUlMDo4uklvg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTEyOEtXIn0.x1vYzUE-E2XBWva9OPuwtqfQaf9rlJCIBAyAe6N2q2kWfJrkxGxFsQ.gAwe78dyODFaoP2IOityAA.Yh5YfovkWxGBNAs1sVhvXow_2izHHsBiYEc9JYD6kVg.mio1p3ncp2wLEaEaRa7P0w",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTEyOEtXIn0.szGrdnmF7D5put2aRBvSSFfp0vRgkRGYaafijJIqAF6PWd1IxsysZRV8aQkQOW1cB6d0fXsTfYM.Ru25LVOOk4xhaK-cIZ0ThA.pF9Ok5zot7elVqXFW5YYHV8MuF9gVGzpQnG1XDs_g_w.-7la0uwcNPpteev185pMHZjbVDXlrec8",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTEyOEtXIn0.cz-hRv0xR5CnOcnoRWNK8Q9poyVYzRCVTjfmEXQN6xPOZUkJ3zKNqb8Pir_FS0o2TVvxmIbuxeISeATTR2Ttx_YGCNgMkc93.SF5rEQT94lZR-UORcMKqGw.xphygoU7zE0ZggOczXCi_ytt-Evln8CL-7WLDlWcUHg.5h99r8xCCwP2PgDbZqzCJ13oFfB2vZWetD5qZjmmVho",
|
||||
},
|
||||
[]string{
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoiVWR5WUVKdEJ5ZTA5dzdjclY0cXI1QSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiZlBBV0QwUmdSbHlFdktQcCJ9.P1uTfTuH-imL-NJJMpuTRA.22yqZ1NIfx3KNPgc.hORWZaTSgni1FS-JT90vJly-cU37qTn-tWSqTg.gMN0ufXF92rSXupTtBNkhA",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoiOU9qX3B2LTJSNW5lZl9YbWVkUWltUSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiY3BybGEwYUYzREVQNmFJTSJ9.6NVpAm_APiC7km2v-oNR8g23K9U_kf1-.jIg-p8tNwSvwxch0.1i-GPaxS4qR6Gy4tzeVtSdRFRSKQSMpmn-VhzA.qhFWPqtA6vVPl7OM3DThsA",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiOVc3THg3MVhGQVJCb3NaLVZ5dXc4ZyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiZ1N4ZE5heFdBSVBRR0tHYiJ9.3YjPz6dVQwAtCekvtXiHZrooOUlmCsMSvyfwmGwdrOA.hA_C0IDJmGaRzsB0.W4l7OPqpFxiVOZTGfAlRktquyRTo4cEOk9KurQ.l4bGxOkO_ql_jlPo3Oz3TQ",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiOHJYbWl2WXFWZjNfbHhhd2NUbHJoUSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiVXBWeXprVTNKcjEwYXRqYyJ9.8qft-Q_xqUbo5j_aVrVNHchooeLttR4Kb6j01O8k98M.hXO-5IKBYCL9UdwBFVm0tg.EBM4lCZX_K6tfqYmfoDxVPHcf6cT--AegXTTjfSqsIw.Of8xUvEQSh3xgFT3uENnAg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiVnItSnVaX0tqV2hSWWMzdzFwZ3cwdyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiRGg2R3dISVBVS3ljZGNZeCJ9.YSEDjCnGWr_n9H94AvLoRnwm6bdU9w6-Q67k-QQRVcKRd6673pgH9zEF9A9Dt6o1.gcmVN4kxqBuMq6c7GrK3UQ.vWzJb0He6OY1lhYYjYS7CLh55REAAq1O7yNN-ND4R5Q.OD0B6nwyFaDr_92ysDOtlVnJaeoIqhGw",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoieEtad1BGYURpQ3NqUnBqZUprZHhmZyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoieTVHRFdteXdkb2R1SDJlYyJ9.AW0gbhWqlptOQ1y9aoNVwrTIIkBfrp33C2OWJsbrDRk6lhxg_IgFhMDTE37moReySGUtttC4CXQD_7etHmd3Hw.OvKXK-aRKlXHOpJQ9ZY_YQ.Ngv7WarDDvR2uBj_DavPAR3DYuIaygvSSdcHrc8-ZqM.MJ6ElitzFCKf_0h5fIJw8uOLC6ps7dKZPozF8juQmUY",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTE5MktXIn0.8qu63pppcSvp1vv37WrZ44qcCTg7dQMA.cDp-f8dJTrDEpZW4.H6OBJYs4UvFR_IZHLYQZxB6u9a0wOdAif2LNfQ.1dB-id0UIwRSlmwHx5BJCg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTE5MktXIn0._FdoKQvC8qUs7K0upriEihUwztK8gOwonXpOxdIwrfs.UO38ok8gDdpLVa1T.x1GvHdVCy4fxoQRg-OQK4Ez3jDOvu9gllLPeEA.3dLeZGIprh_nHizOTVi1xw",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTE5MktXIn0.uzCJskgSIK6VkjJIu-dQi18biqaY0INc_A1Ehx0oESafgtR99_n4IA.W2eKK8Y14WwTowI_.J2cJC7R6Bz6maR0s1UBMPyRi5BebNUAmof4pvw.-7w6htAlc4iUsOJ6I04rFg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTE5MktXIn0.gImQeQETp_6dfJypFDPLlv7c5pCzuq86U16gzrLiCXth6X9XfxJpvQ.YlC4MxjtLWrsyEvlFhvsqw.Vlpvmg9F3gkz4e1xG01Yl2RXx-jG99rF5UvCxOBXSLc.RZUrU_FoR5bG3M-j3GY0Dw",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTE5MktXIn0.T2EfQ6Tu2wJyRMgZzfvBYmQNCCfdMudMrg86ibEMVAOUKJPtR3WMPEb_Syy9p2VjrLKRlv7nebo.GPc8VbarPPRtzIRATB8NsA.ugPCqLvVLwh55bWlwjsFkmWzJ31z5z-wuih2oJqmG_U.m7FY3EjvV6mKosEYJ5cY7ezFoVQoJS8X",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTE5MktXIn0.OgLMhZ-2ZhslQyHfzOfyC-qmT6bNg9AdpP59B4jtyxWkQu3eW475WCdiAjojjeyBtVRGQ5vOomwaOIFejY_IekzH6I_taii3.U9x44MF6Wyz5TIwIzwhoxQ.vK7yvSF2beKdNxNY_7n4XdF7JluCGZoxdFJyTJVkSmI.bXRlI8KL-g7gpprQxGmXjVYjYghhWJq7mlCfWI8q2uA",
|
||||
},
|
||||
[]string{
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoiR3BjX3pfbjduZjJVZlEtWGdsaTBaQSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiUk40eUdhOVlvYlFhUmZ1TCJ9.Q4ukD6_hZpmASAVcqWJ9Wg.Zfhny_1WNdlp4fH-.3sekDCjkExQCcv28ZW4yrcFnz0vma3vgoenSXA.g8_Ird2Y0itTCDP61du-Yg",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoiWC05UkNVWVh4U3NRelcwelVJS01VUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiY3JNMnJfa3RrdWpyQ1h5OSJ9.c0q2jCxxV4y1h9u_Xvn7FqUDnbkmNEG4.S_noOTZKuUo9z1l6.ez0RdA25vXMUGH96iXmj3DEVox0J7TasJMnzgg.RbuSPTte_NzTtEEokbc5Ig",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiWmwyaDFpUW11QWZWd2lJeVp5RHloZyIsImFsZyI6IkEyNTZHQ01LVyIsIml2Ijoib19xZmljb0N0NzNzRWo1QyJ9.NpJxRJ0aqcpekD6HU2u9e6_pL_11JXjWvjfeQnAKkZU.4c5qBcBBrMWi27Lf.NKwNIb4b6cRDJ1TwMKsPrjs7ADn6aNoBdQClVw.yNWmSSRBqQfIQObzj8zDqw",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiMXdwVEI3LWhjdzZUVXhCbVh2UzdhUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiOUdIVnZJaDZ0a09vX2pHUSJ9.MFgIhp9mzlq9hoPqqKVKHJ3HL79EBYtV4iNhD63yqiU.UzW5iq8ou21VpZYJgKEN8A.1gOEzA4uAPvHP76GMfs9uLloAV10mKaxiZVAeL7iQA0.i1X_2i0bCAz-soXF9bI_zw",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiNThocUtsSk15Y1BFUEFRUlNfSzlNUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiUDh3aTBWMTluVnZqNXpkOSJ9.FXidOWHNFJODO74Thq3J2cC-Z2B8UZkn7SikeosU0bUK6Jx_lzzmUZ-Lafadpdpj.iLfcDbpuBKFiSfiBzUQc7Q.VZK-aD7BFspqfvbwa0wE2wwWxdomzk2IKMetFe8bI44.7wC6rJRGa4x48xbYMd6NH9VzK8uNn4Cb",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoicGcwOEpUcXdzMXdEaXBaRUlpVExoQSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiSlpodk9CdU1RUDFFZTZTNSJ9.wqVgTPm6TcYCTkpbwmn9sW4mgJROH2A3dIdSXo5oKIQUIVbQsmy7KXH8UYO2RS9slMGtb869C8o0My67GKg9dQ.ogrRiLlqjB1S5j-7a05OwA.2Y_LyqhU4S_RXMsB74bxcBacd23J2Sp5Lblw-sOkaUY.XGMiYoU-f3GaEzSvG41vpJP2DMGbeDFoWmkUGLUjc4M",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTI1NktXIn0.QiIZm9NYfahqYFIbiaoUhCCHjotHMkup.EsU0XLn4FjzzCILn.WuCoQkm9vzo95E7hxBtfYpt-Mooc_vmSTyzj6Q.NbeeYVy6gQPlmhoWDrZwaQ",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTI1NktXIn0.1ol3j_Lt0Os3UMe2Gypj0o8b77k0FSmqD7kNRNoMa9U.vZ2HMTgN2dgUd42h.JvNcy8-c8sYzOC089VtFSg2BOQx3YF8CqSTuJw.t03LRioWWKN3d7SjinU6SQ",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTI1NktXIn0.gbkk03l1gyrE9qGEMVtORiyyUqKsgzbqjLd8lw0RQ07WWn--TV4BgA.J8ThH4ac2UhSsMIP.g-W1piEGrdi3tNwQDJXpYm3fQjTf82mtVCrCOg.-vY05P4kiB9FgF2vwrSeXQ",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTI1NktXIn0.k86pQs7gmQIzuIWRFwesF32XY2xi1WbYxi7XUf_CYlOlehwGCTINHg.3NcC9VzfQgsECISKf4xy-g.v2amdo-rgeGsg-II_tvPukX9D-KAP27xxf2uQJ277Ws.E4LIE3fte3glAnPpnd8D9Q",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTI1NktXIn0.b8iN0Am3fCUvj7sBd7Z0lpfzBjh1MOgojV7J5rDfrcTU3b35RGYgEV1RdcrtUTBgUwITDjmU7jM.wsSDBFghDga_ERv36I2AOg.6uJsucCb2YReFOJGBdo4zidTIKLUmZBIXfm_M0AJpKk.YwdAfXI3HHcw2wLSnfCRtw4huZQtSKhz",
|
||||
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTI1NktXIn0.akY9pHCbkHPh5VpXIrX0At41XnJIKBR9iMMkf301vKeJNAZYJTxWzeJhFd-DhQ47tMctc3YYkwZkQ5I_9fGYb_f0oBcw4esh.JNwuuHud78h6S99NO1oBQQ.0RwckPYATBgvw67upkAQ1AezETHc-gh3rryz19i5ryc.3XClRTScgzfMgLCHxHHoRF8mm9VVGXv_Ahtx65PskKQ",
|
||||
},
|
||||
}
|
||||
|
||||
for i, msgs := range aesSampleMessages {
|
||||
for _, msg := range msgs {
|
||||
obj, err := ParseEncrypted(msg)
|
||||
if err != nil {
|
||||
t.Error("unable to parse message", msg, err)
|
||||
continue
|
||||
}
|
||||
plaintext, err := obj.Decrypt(aesTestKeys[i])
|
||||
if err != nil {
|
||||
t.Error("unable to decrypt message", msg, err)
|
||||
continue
|
||||
}
|
||||
if string(plaintext) != "Lorem ipsum dolor sit amet" {
|
||||
t.Error("plaintext is not what we expected for msg", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors generated with jose4j
|
||||
func TestSampleJose4jJWEMessagesECDH(t *testing.T) {
|
||||
ecTestKey := &ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
Curve: elliptic.P256(),
|
||||
X: fromBase64Int("weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ"),
|
||||
Y: fromBase64Int("e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck"),
|
||||
},
|
||||
D: fromBase64Int("VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"),
|
||||
}
|
||||
|
||||
ecSampleMessages := []string{
|
||||
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJTQzAtRnJHUkVvVkpKSmg1TGhORmZqZnFXMC1XSUFyd3RZMzJzQmFQVVh3IiwieSI6ImFQMWlPRENveU9laTVyS1l2VENMNlRMZFN5UEdUN0djMnFsRnBwNXdiWFEiLCJjcnYiOiJQLTI1NiJ9fQ..3mifklTnTTGuA_etSUBBCw.dj8KFM8OlrQ3rT35nHcHZ7A5p84VB2OZb054ghSjS-M.KOIgnJjz87LGqMtikXGxXw",
|
||||
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTE5MkNCQy1IUzM4NCIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJUaHRGc0lRZ1E5MkZOYWFMbUFDQURLbE93dmNGVlRORHc4ampfWlJidUxjIiwieSI6IjJmRDZ3UXc3YmpYTm1nVThXMGpFbnl5ZUZkX3Y4ZmpDa3l1R29vTFhGM0EiLCJjcnYiOiJQLTI1NiJ9fQ..90zFayMkKc-fQC_19f6P3A.P1Y_7lMnfkUQOXW_en31lKZ3zAn1nEYn6fXLjmyVPrQ.hrgwy1cePVfhMWT0h-crKTXldglHZ-4g",
|
||||
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImVwayI6eyJrdHkiOiJFQyIsIngiOiI5R1Z6c3VKNWgySl96UURVUFR3WU5zUkFzVzZfY2RzN0pELVQ2RDREQ1ZVIiwieSI6InFZVGl1dVU4aTB1WFpoaS14VGlRNlZJQm5vanFoWENPVnpmWm1pR2lRTEUiLCJjcnYiOiJQLTI1NiJ9fQ..v2reRlDkIsw3eWEsTCc1NA.0qakrFdbhtBCTSl7EREf9sxgHBP9I-Xw29OTJYnrqP8.54ozViEBYYmRkcKp7d2Ztt4hzjQ9Vb5zCeijN_RQrcI",
|
||||
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiOElUemg3VVFaaUthTWtfME9qX1hFaHZENXpUWjE2Ti13WVdjeTJYUC1tdyIsInkiOiJPNUJiVEk0bUFpU005ZmpCejBRU3pXaU5vbnl3cWlQLUN0RGgwdnNGYXNRIiwiY3J2IjoiUC0yNTYifX0.D3DP3wqPvJv4TYYfhnfrOG6nsM-MMH_CqGfnOGjgdXHNF7xRwEJBOA.WL9Kz3gNYA7S5Rs5mKcXmA.EmQkXhO_nFqAwxJWaM0DH4s3pmCscZovB8YWJ3Ru4N8.Bf88uzwfxiyTjpejU5B0Ng",
|
||||
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiMjlJMk4zRkF0UlBlNGhzYjRLWlhTbmVyV0wyTVhtSUN1LXJJaXhNSHpJQSIsInkiOiJvMjY1bzFReEdmbDhzMHQ0U1JROS00RGNpc3otbXh4NlJ6WVF4SktyeWpJIiwiY3J2IjoiUC0yNTYifX0.DRmsmXz6fCnLc_njDIKdpM7Oc4jTqd_yd9J94TOUksAstEUkAl9Ie3Wg-Ji_LzbdX2xRLXIimcw.FwJOHPQhnqKJCfxt1_qRnQ.ssx3q1ZYILsMTln5q-K8HVn93BVPI5ViusstKMxZzRs.zzcfzWNYSdNDdQ4CiHfymj0bePaAbVaT",
|
||||
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiRUp6bTViQnRzVXJNYTl2Y1Q2d1hZRXI3ZjNMcjB0N1V4SDZuZzdGcFF0VSIsInkiOiJRYTNDSDllVTFXYjItdFdVSDN3Sk9fTDVMZXRsRUlMQWNkNE9XR2tFd0hZIiwiY3J2IjoiUC0yNTYifX0.5WxwluZpVWAOJdVrsnDIlEc4_wfRE1gXOaQyx_rKkElNz157Ykf-JsAD7aEvXfx--NKF4js5zYyjeCtxWBhRWPOoNNZJlqV_.Iuo82-qsP2S1SgQQklAnrw.H4wB6XoLKOKWCu6Y3LPAEuHkvyvr-xAh4IBm53uRF8g._fOLKq0bqDZ8KNjni_MJ4olHNaYz376dV9eNmp9O9PU",
|
||||
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiZktNSG5sRkoxajBTSnJ3WGtVWlpaX3BtWHdUQlJtcHhlaTkxdUpaczUycyIsInkiOiJLRkxKaXhEUTJQcjEybWp1aFdYb3pna2U1V3lhWnhmTWlxZkJ0OEJpbkRvIiwiY3J2IjoiUC0yNTYifX0.2LSD2Mw4tyYJyfsmpVmzBtJRd12jMEYGdlhFbaXIbKi5A33CGNQ1tg.s40aAjmZOvK8Us86FCBdHg.jpYSMAKp___oMCoWM495mTfbi_YC80ObeoCmGE3H_gs.A6V-jJJRY1yz24CaXGUbzg",
|
||||
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiSDRxcFUzeWtuRktWRnV4SmxLa3NZSE5ieHF3aXM0WWtCVVFHVE1Td05JQSIsInkiOiJHb0lpRUZaUGRRSHJCbVR4ZTA3akJoZmxrdWNqUjVoX1QwNWVXc3Zib0prIiwiY3J2IjoiUC0yNTYifX0.KTrwwV2uzD--gf3PGG-kjEAGgi7u0eMqZPZfa4kpyFGm3x8t2m1NHdz3t9rfiqjuaqsxPKhF4gs.cu16fEOzYaSxhHu_Ht9w4g.BRJdxVBI9spVtY5KQ6gTR4CNcKvmLUMKZap0AO-RF2I.DZyUaa2p6YCIaYtjWOjC9GN_VIYgySlZ",
|
||||
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoieDBYSGRkSGM2Q0ktSnlfbUVMOEZZRExhWnV0UkVFczR4c3BMQmcwZk1jbyIsInkiOiJEa0xzOUJGTlBkTTVTNkpLYVJ3cnV1TWMwcUFzWW9yNW9fZWp6NXBNVXFrIiwiY3J2IjoiUC0yNTYifX0.mfCxJ7JYIqTMqcAh5Vp2USF0eF7OhOeluqda7YagOUJNwxA9wC9o23DSoLUylfrZUfanZrJJJcG69awlv-LY7anOLHlp3Ht5.ec48A_JWb4qa_PVHWZaTfQ.kDAjIDb3LzJpfxNh-DiAmAuaKMYaOGSTb0rkiJLuVeY.oxGCpPlii4pr89XMk4b9s084LucTqPGU6TLbOW2MZoc",
|
||||
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiQXB5TnlqU2d0bmRUcFg0eENYenNDRnZva1l3X18weXg2dGRUYzdPUUhIMCIsInkiOiJYUHdHMDVDaW1vOGlhWmxZbDNsMEp3ZllhY1FZWHFuM2RRZEJUWFpldDZBIiwiY3J2IjoiUC0yNTYifX0.yTA2PwK9IPqkaGPenZ9R-gOn9m9rvcSEfuX_Nm8AkuwHIYLzzYeAEA.ZW1F1iyHYKfo-YoanNaIVg.PouKQD94DlPA5lbpfGJXY-EJhidC7l4vSayVN2vVzvA.MexquqtGaXKUvX7WBmD4bA",
|
||||
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiaDRWeGNzNVUzWk1fTlp4WmJxQ3hMTVB5UmEtR2ktSVNZa0xDTzE1RHJkZyIsInkiOiJFeVotS3dWNVE5OXlnWk5zU0lpSldpR3hqbXNLUk1WVE5sTTNSd1VYTFRvIiwiY3J2IjoiUC0yNTYifX0.wo56VISyL1QAbi2HLuVut5NGF2FvxKt7B8zHzJ3FpmavPozfbVZV08-GSYQ6jLQWJ4xsO80I4Kg.3_9Bo5ozvD96WHGhqp_tfQ.48UkJ6jk6WK70QItb2QZr0edKH7O-aMuVahTEeqyfW4.ulMlY2tbC341ct20YSmNdtc84FRz1I4g",
|
||||
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiN0xZRzZZWTJkel9ZaGNvNnRCcG1IX0tPREQ2X2hwX05tajdEc1c2RXgxcyIsInkiOiI5Y2lPeDcwUkdGT0tpVnBRX0NHQXB5NVlyeThDazBmUkpwNHVrQ2tjNmQ0IiwiY3J2IjoiUC0yNTYifX0.bWwW3J80k46HG1fQAZxUroko2OO8OKkeRavr_o3AnhJDMvp78OR229x-fZUaBm4uWv27_Yjm0X9T2H2lhlIli2Rl9v1PNC77.1NmsJBDGI1fDjRzyc4mtyA.9KfCFynQj7LmJq08qxAG4c-6ZPz1Lh3h3nUbgVwB0TI.cqech0d8XHzWfkWqgKZq1SlAfmO0PUwOsNVkuByVGWk",
|
||||
}
|
||||
|
||||
for _, msg := range ecSampleMessages {
|
||||
obj, err := ParseEncrypted(msg)
|
||||
if err != nil {
|
||||
t.Error("unable to parse message", msg, err)
|
||||
continue
|
||||
}
|
||||
plaintext, err := obj.Decrypt(ecTestKey)
|
||||
if err != nil {
|
||||
t.Error("unable to decrypt message", msg, err)
|
||||
continue
|
||||
}
|
||||
if string(plaintext) != "Lorem ipsum dolor sit amet." {
|
||||
t.Error("plaintext is not what we expected for msg", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package jose
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
|
|
@ -24,10 +25,12 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// rawJsonWebKey represents a public or private key in JWK format, used for parsing/serializing.
|
||||
type rawJsonWebKey struct {
|
||||
Use string `json:"use,omitempty"`
|
||||
Kty string `json:"kty,omitempty"`
|
||||
Kid string `json:"kid,omitempty"`
|
||||
Crv string `json:"crv,omitempty"`
|
||||
|
|
@ -53,6 +56,7 @@ type JsonWebKey struct {
|
|||
Key interface{}
|
||||
KeyID string
|
||||
Algorithm string
|
||||
Use string
|
||||
}
|
||||
|
||||
// MarshalJSON serializes the given key to its JSON representation.
|
||||
|
|
@ -70,7 +74,7 @@ func (k JsonWebKey) MarshalJSON() ([]byte, error) {
|
|||
case *rsa.PrivateKey:
|
||||
raw, err = fromRsaPrivateKey(key)
|
||||
default:
|
||||
return nil, fmt.Errorf("square/go-jose: unkown key type '%s'", reflect.TypeOf(key))
|
||||
return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -79,6 +83,7 @@ func (k JsonWebKey) MarshalJSON() ([]byte, error) {
|
|||
|
||||
raw.Kid = k.KeyID
|
||||
raw.Alg = k.Algorithm
|
||||
raw.Use = k.Use
|
||||
|
||||
return json.Marshal(raw)
|
||||
}
|
||||
|
|
@ -110,11 +115,79 @@ func (k *JsonWebKey) UnmarshalJSON(data []byte) (err error) {
|
|||
}
|
||||
|
||||
if err == nil {
|
||||
*k = JsonWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg}
|
||||
*k = JsonWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// JsonWebKeySet represents a JWK Set object.
|
||||
type JsonWebKeySet struct {
|
||||
Keys []JsonWebKey `json:"keys"`
|
||||
}
|
||||
|
||||
// Key convenience method returns keys by key ID. Specification states
|
||||
// that a JWK Set "SHOULD" use distinct key IDs, but allows for some
|
||||
// cases where they are not distinct. Hence method returns a slice
|
||||
// of JsonWebKeys.
|
||||
func (s *JsonWebKeySet) Key(kid string) []JsonWebKey {
|
||||
var keys []JsonWebKey
|
||||
for _, key := range s.Keys {
|
||||
if key.KeyID == kid {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
|
||||
const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`
|
||||
|
||||
func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) {
|
||||
coordLength := curveSize(curve)
|
||||
crv, err := curveName(curve)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf(ecThumbprintTemplate, crv,
|
||||
newFixedSizeBuffer(x.Bytes(), coordLength).base64(),
|
||||
newFixedSizeBuffer(y.Bytes(), coordLength).base64()), nil
|
||||
}
|
||||
|
||||
func rsaThumbprintInput(n *big.Int, e int) (string, error) {
|
||||
return fmt.Sprintf(rsaThumbprintTemplate,
|
||||
newBufferFromInt(uint64(e)).base64(),
|
||||
newBuffer(n.Bytes()).base64()), nil
|
||||
}
|
||||
|
||||
// Thumbprint computes the JWK Thumbprint of a key using the
|
||||
// indicated hash algorithm.
|
||||
func (k *JsonWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
|
||||
var input string
|
||||
var err error
|
||||
switch key := k.Key.(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
|
||||
case *ecdsa.PrivateKey:
|
||||
input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
|
||||
case *rsa.PublicKey:
|
||||
input, err = rsaThumbprintInput(key.N, key.E)
|
||||
case *rsa.PrivateKey:
|
||||
input, err = rsaThumbprintInput(key.N, key.E)
|
||||
default:
|
||||
return nil, fmt.Errorf("square/go-jose: unkown key type '%s'", reflect.TypeOf(key))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := hash.New()
|
||||
h.Write([]byte(input))
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
func (key rawJsonWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
|
||||
if key.N == nil || key.E == nil {
|
||||
return nil, fmt.Errorf("square/go-jose: invalid RSA key, missing n/e values")
|
||||
|
|
@ -160,32 +233,50 @@ func (key rawJsonWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
|
|||
|
||||
func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJsonWebKey, error) {
|
||||
if pub == nil || pub.X == nil || pub.Y == nil {
|
||||
return nil, fmt.Errorf("square/go-jose: invalid EC key")
|
||||
return nil, fmt.Errorf("square/go-jose: invalid EC key (nil, or X/Y missing)")
|
||||
}
|
||||
|
||||
name, err := curveName(pub.Curve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size := curveSize(pub.Curve)
|
||||
|
||||
xBytes := pub.X.Bytes()
|
||||
yBytes := pub.Y.Bytes()
|
||||
|
||||
if len(xBytes) > size || len(yBytes) > size {
|
||||
return nil, fmt.Errorf("square/go-jose: invalid EC key (X/Y too large)")
|
||||
}
|
||||
|
||||
key := &rawJsonWebKey{
|
||||
Kty: "EC",
|
||||
X: newBuffer(pub.X.Bytes()),
|
||||
Y: newBuffer(pub.Y.Bytes()),
|
||||
}
|
||||
|
||||
switch pub.Curve {
|
||||
case elliptic.P256():
|
||||
key.Crv = "P-256"
|
||||
case elliptic.P384():
|
||||
key.Crv = "P-384"
|
||||
case elliptic.P521():
|
||||
key.Crv = "P-521"
|
||||
default:
|
||||
return nil, fmt.Errorf("square/go-jose: unsupported/unknown elliptic curve")
|
||||
Crv: name,
|
||||
X: newFixedSizeBuffer(xBytes, size),
|
||||
Y: newFixedSizeBuffer(yBytes, size),
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (key rawJsonWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
||||
if key.N == nil || key.E == nil || key.D == nil || key.P == nil || key.Q == nil {
|
||||
return nil, fmt.Errorf("square/go-jose: invalid RSA private key, missing values")
|
||||
var missing []string
|
||||
switch {
|
||||
case key.N == nil:
|
||||
missing = append(missing, "N")
|
||||
case key.E == nil:
|
||||
missing = append(missing, "E")
|
||||
case key.D == nil:
|
||||
missing = append(missing, "D")
|
||||
case key.P == nil:
|
||||
missing = append(missing, "P")
|
||||
case key.Q == nil:
|
||||
missing = append(missing, "Q")
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
return nil, fmt.Errorf("square/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", "))
|
||||
}
|
||||
|
||||
rv := &rsa.PrivateKey{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,515 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCurveSize(t *testing.T) {
|
||||
size256 := curveSize(elliptic.P256())
|
||||
size384 := curveSize(elliptic.P384())
|
||||
size521 := curveSize(elliptic.P521())
|
||||
if size256 != 32 {
|
||||
t.Error("P-256 have 32 bytes")
|
||||
}
|
||||
if size384 != 48 {
|
||||
t.Error("P-384 have 48 bytes")
|
||||
}
|
||||
if size521 != 66 {
|
||||
t.Error("P-521 have 66 bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundtripRsaPrivate(t *testing.T) {
|
||||
jwk, err := fromRsaPrivateKey(rsaTestKey)
|
||||
if err != nil {
|
||||
t.Error("problem constructing JWK from rsa key", err)
|
||||
}
|
||||
|
||||
rsa2, err := jwk.rsaPrivateKey()
|
||||
if err != nil {
|
||||
t.Error("problem converting RSA private -> JWK", err)
|
||||
}
|
||||
|
||||
if rsa2.N.Cmp(rsaTestKey.N) != 0 {
|
||||
t.Error("RSA private N mismatch")
|
||||
}
|
||||
if rsa2.E != rsaTestKey.E {
|
||||
t.Error("RSA private E mismatch")
|
||||
}
|
||||
if rsa2.D.Cmp(rsaTestKey.D) != 0 {
|
||||
t.Error("RSA private D mismatch")
|
||||
}
|
||||
if len(rsa2.Primes) != 2 {
|
||||
t.Error("RSA private roundtrip expected two primes")
|
||||
}
|
||||
if rsa2.Primes[0].Cmp(rsaTestKey.Primes[0]) != 0 {
|
||||
t.Error("RSA private P mismatch")
|
||||
}
|
||||
if rsa2.Primes[1].Cmp(rsaTestKey.Primes[1]) != 0 {
|
||||
t.Error("RSA private Q mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRsaPrivateInsufficientPrimes(t *testing.T) {
|
||||
brokenRsaPrivateKey := rsa.PrivateKey{
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: rsaTestKey.N,
|
||||
E: rsaTestKey.E,
|
||||
},
|
||||
D: rsaTestKey.D,
|
||||
Primes: []*big.Int{rsaTestKey.Primes[0]},
|
||||
}
|
||||
|
||||
_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
|
||||
if err != ErrUnsupportedKeyType {
|
||||
t.Error("expected unsupported key type error, got", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRsaPrivateExcessPrimes(t *testing.T) {
|
||||
brokenRsaPrivateKey := rsa.PrivateKey{
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: rsaTestKey.N,
|
||||
E: rsaTestKey.E,
|
||||
},
|
||||
D: rsaTestKey.D,
|
||||
Primes: []*big.Int{
|
||||
rsaTestKey.Primes[0],
|
||||
rsaTestKey.Primes[1],
|
||||
big.NewInt(3),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
|
||||
if err != ErrUnsupportedKeyType {
|
||||
t.Error("expected unsupported key type error, got", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundtripEcPublic(t *testing.T) {
|
||||
for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
|
||||
jwk, err := fromEcPublicKey(&ecTestKey.PublicKey)
|
||||
|
||||
ec2, err := jwk.ecPublicKey()
|
||||
if err != nil {
|
||||
t.Error("problem converting ECDSA private -> JWK", i, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
|
||||
t.Error("ECDSA private curve mismatch", i)
|
||||
}
|
||||
if ec2.X.Cmp(ecTestKey.X) != 0 {
|
||||
t.Error("ECDSA X mismatch", i)
|
||||
}
|
||||
if ec2.Y.Cmp(ecTestKey.Y) != 0 {
|
||||
t.Error("ECDSA Y mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundtripEcPrivate(t *testing.T) {
|
||||
for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
|
||||
jwk, err := fromEcPrivateKey(ecTestKey)
|
||||
|
||||
ec2, err := jwk.ecPrivateKey()
|
||||
if err != nil {
|
||||
t.Error("problem converting ECDSA private -> JWK", i, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
|
||||
t.Error("ECDSA private curve mismatch", i)
|
||||
}
|
||||
if ec2.X.Cmp(ecTestKey.X) != 0 {
|
||||
t.Error("ECDSA X mismatch", i)
|
||||
}
|
||||
if ec2.Y.Cmp(ecTestKey.Y) != 0 {
|
||||
t.Error("ECDSA Y mismatch", i)
|
||||
}
|
||||
if ec2.D.Cmp(ecTestKey.D) != 0 {
|
||||
t.Error("ECDSA D mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalJWK(t *testing.T) {
|
||||
kid := "DEADBEEF"
|
||||
|
||||
for i, key := range []interface{}{ecTestKey256, ecTestKey384, ecTestKey521, rsaTestKey} {
|
||||
for _, use := range []string{"", "sig", "enc"} {
|
||||
jwk := JsonWebKey{Key: key, KeyID: kid, Algorithm: "foo"}
|
||||
if use != "" {
|
||||
jwk.Use = use
|
||||
}
|
||||
|
||||
jsonbar, err := jwk.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Error("problem marshaling", i, err)
|
||||
}
|
||||
|
||||
var jwk2 JsonWebKey
|
||||
err = jwk2.UnmarshalJSON(jsonbar)
|
||||
if err != nil {
|
||||
t.Error("problem unmarshalling", i, err)
|
||||
}
|
||||
|
||||
jsonbar2, err := jwk2.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Error("problem marshaling", i, err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(jsonbar, jsonbar2) {
|
||||
t.Error("roundtrip should not lose information", i)
|
||||
}
|
||||
if jwk2.KeyID != kid {
|
||||
t.Error("kid did not roundtrip JSON marshalling", i)
|
||||
}
|
||||
|
||||
if jwk2.Algorithm != "foo" {
|
||||
t.Error("alg did not roundtrip JSON marshalling", i)
|
||||
}
|
||||
|
||||
if jwk2.Use != use {
|
||||
t.Error("use did not roundtrip JSON marshalling", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalNonPointer(t *testing.T) {
|
||||
type EmbedsKey struct {
|
||||
Key JsonWebKey
|
||||
}
|
||||
|
||||
keyJson := []byte(`{
|
||||
"e": "AQAB",
|
||||
"kty": "RSA",
|
||||
"n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw"
|
||||
}`)
|
||||
var parsedKey JsonWebKey
|
||||
err := json.Unmarshal(keyJson, &parsedKey)
|
||||
if err != nil {
|
||||
t.Error(fmt.Sprintf("Error unmarshalling key: %v", err))
|
||||
return
|
||||
}
|
||||
ek := EmbedsKey{
|
||||
Key: parsedKey,
|
||||
}
|
||||
out, err := json.Marshal(ek)
|
||||
if err != nil {
|
||||
t.Error(fmt.Sprintf("Error marshalling JSON: %v", err))
|
||||
return
|
||||
}
|
||||
expected := "{\"Key\":{\"kty\":\"RSA\",\"n\":\"vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw\",\"e\":\"AQAB\"}}"
|
||||
if string(out) != expected {
|
||||
t.Error("Failed to marshal embedded non-pointer JWK properly:", string(out))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalInvalid(t *testing.T) {
|
||||
// Make an invalid curve coordinate by creating a byte array that is one
|
||||
// byte too large, and setting the first byte to 1 (otherwise it's just zero).
|
||||
invalidCoord := make([]byte, curveSize(ecTestKey256.Curve)+1)
|
||||
invalidCoord[0] = 1
|
||||
|
||||
keys := []interface{}{
|
||||
// Empty keys
|
||||
&rsa.PrivateKey{},
|
||||
&ecdsa.PrivateKey{},
|
||||
// Invalid keys
|
||||
&ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
// Missing values in pub key
|
||||
Curve: elliptic.P256(),
|
||||
},
|
||||
},
|
||||
&ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
// Invalid curve
|
||||
Curve: nil,
|
||||
X: ecTestKey256.X,
|
||||
Y: ecTestKey256.Y,
|
||||
},
|
||||
},
|
||||
&ecdsa.PrivateKey{
|
||||
// Valid pub key, but missing priv key values
|
||||
PublicKey: ecTestKey256.PublicKey,
|
||||
},
|
||||
&ecdsa.PrivateKey{
|
||||
// Invalid pub key, values too large
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
Curve: ecTestKey256.Curve,
|
||||
X: big.NewInt(0).SetBytes(invalidCoord),
|
||||
Y: big.NewInt(0).SetBytes(invalidCoord),
|
||||
},
|
||||
D: ecTestKey256.D,
|
||||
},
|
||||
nil,
|
||||
}
|
||||
|
||||
for i, key := range keys {
|
||||
jwk := JsonWebKey{Key: key}
|
||||
_, err := jwk.MarshalJSON()
|
||||
if err == nil {
|
||||
t.Error("managed to serialize invalid key", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebKeyVectorsInvalid(t *testing.T) {
|
||||
keys := []string{
|
||||
// Invalid JSON
|
||||
"{X",
|
||||
// Empty key
|
||||
"{}",
|
||||
// Invalid RSA keys
|
||||
`{"kty":"RSA"}`,
|
||||
`{"kty":"RSA","e":""}`,
|
||||
`{"kty":"RSA","e":"XXXX"}`,
|
||||
`{"kty":"RSA","d":"XXXX"}`,
|
||||
// Invalid EC keys
|
||||
`{"kty":"EC","crv":"ABC"}`,
|
||||
`{"kty":"EC","crv":"P-256"}`,
|
||||
`{"kty":"EC","crv":"P-256","d":"XXX"}`,
|
||||
`{"kty":"EC","crv":"ABC","d":"dGVzdA","x":"dGVzdA"}`,
|
||||
`{"kty":"EC","crv":"P-256","d":"dGVzdA","x":"dGVzdA"}`,
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
var jwk2 JsonWebKey
|
||||
err := jwk2.UnmarshalJSON([]byte(key))
|
||||
if err == nil {
|
||||
t.Error("managed to parse invalid key:", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors from RFC 7520
|
||||
var cookbookJWKs = []string{
|
||||
// EC Public
|
||||
stripWhitespace(`{
|
||||
"kty": "EC",
|
||||
"kid": "bilbo.baggins@hobbiton.example",
|
||||
"use": "sig",
|
||||
"crv": "P-521",
|
||||
"x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
|
||||
A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
|
||||
"y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
|
||||
SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
|
||||
}`),
|
||||
|
||||
// EC Private
|
||||
stripWhitespace(`{
|
||||
"kty": "EC",
|
||||
"kid": "bilbo.baggins@hobbiton.example",
|
||||
"use": "sig",
|
||||
"crv": "P-521",
|
||||
"x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
|
||||
A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
|
||||
"y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
|
||||
SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1",
|
||||
"d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zb
|
||||
KipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt"
|
||||
}`),
|
||||
|
||||
// RSA Public
|
||||
stripWhitespace(`{
|
||||
"kty": "RSA",
|
||||
"kid": "bilbo.baggins@hobbiton.example",
|
||||
"use": "sig",
|
||||
"n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
|
||||
-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
|
||||
wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
|
||||
oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
|
||||
3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
|
||||
LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
|
||||
HdrNP5zw",
|
||||
"e": "AQAB"
|
||||
}`),
|
||||
|
||||
// RSA Private
|
||||
stripWhitespace(`{"kty":"RSA",
|
||||
"kid":"juliet@capulet.lit",
|
||||
"use":"enc",
|
||||
"n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy
|
||||
O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP
|
||||
8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0
|
||||
Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X
|
||||
OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1
|
||||
_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
|
||||
"e":"AQAB",
|
||||
"d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS
|
||||
NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U
|
||||
vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu
|
||||
ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu
|
||||
rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a
|
||||
hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
|
||||
"p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf
|
||||
QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8
|
||||
UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
|
||||
"q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I
|
||||
edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK
|
||||
rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
|
||||
"dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3
|
||||
tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w
|
||||
Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
|
||||
"dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9
|
||||
GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy
|
||||
mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
|
||||
"qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq
|
||||
abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o
|
||||
Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}`),
|
||||
}
|
||||
|
||||
// SHA-256 thumbprints of the above keys, hex-encoded
|
||||
var cookbookJWKThumbprints = []string{
|
||||
"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
|
||||
"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
|
||||
"f63838e96077ad1fc01c3f8405774dedc0641f558ebb4b40dccf5f9b6d66a932",
|
||||
"0fc478f8579325fcee0d4cbc6d9d1ce21730a6e97e435d6008fb379b0ebe47d4",
|
||||
}
|
||||
|
||||
func TestWebKeyVectorsValid(t *testing.T) {
|
||||
for _, key := range cookbookJWKs {
|
||||
var jwk2 JsonWebKey
|
||||
err := jwk2.UnmarshalJSON([]byte(key))
|
||||
if err != nil {
|
||||
t.Error("unable to parse valid key:", key, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestThumbprint(t *testing.T) {
|
||||
for i, key := range cookbookJWKs {
|
||||
var jwk2 JsonWebKey
|
||||
err := jwk2.UnmarshalJSON([]byte(key))
|
||||
if err != nil {
|
||||
t.Error("unable to parse valid key:", key, err)
|
||||
}
|
||||
|
||||
tp, err := jwk2.Thumbprint(crypto.SHA256)
|
||||
if err != nil {
|
||||
t.Error("unable to compute thumbprint:", key, err)
|
||||
}
|
||||
|
||||
tpHex := hex.EncodeToString(tp)
|
||||
if cookbookJWKThumbprints[i] != tpHex {
|
||||
t.Error("incorrect thumbprint:", i, cookbookJWKThumbprints[i], tpHex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalJWKSet(t *testing.T) {
|
||||
jwk1 := JsonWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
|
||||
jwk2 := JsonWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
|
||||
var set JsonWebKeySet
|
||||
set.Keys = append(set.Keys, jwk1)
|
||||
set.Keys = append(set.Keys, jwk2)
|
||||
|
||||
jsonbar, err := json.Marshal(&set)
|
||||
if err != nil {
|
||||
t.Error("problem marshalling set", err)
|
||||
}
|
||||
var set2 JsonWebKeySet
|
||||
err = json.Unmarshal(jsonbar, &set2)
|
||||
if err != nil {
|
||||
t.Error("problem unmarshalling set", err)
|
||||
}
|
||||
jsonbar2, err := json.Marshal(&set2)
|
||||
if err != nil {
|
||||
t.Error("problem marshalling set", err)
|
||||
}
|
||||
if !bytes.Equal(jsonbar, jsonbar2) {
|
||||
t.Error("roundtrip should not lose information")
|
||||
}
|
||||
}
|
||||
|
||||
var JWKSetDuplicates = stripWhitespace(`{
|
||||
"keys": [{
|
||||
"kty": "RSA",
|
||||
"kid": "exclude-me",
|
||||
"use": "sig",
|
||||
"n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
|
||||
-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
|
||||
wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
|
||||
oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
|
||||
3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
|
||||
LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
|
||||
HdrNP5zw",
|
||||
"e": "AQAB"
|
||||
}],
|
||||
"keys": [{
|
||||
"kty": "RSA",
|
||||
"kid": "include-me",
|
||||
"use": "sig",
|
||||
"n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
|
||||
-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
|
||||
wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
|
||||
oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
|
||||
3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
|
||||
LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
|
||||
HdrNP5zw",
|
||||
"e": "AQAB"
|
||||
}],
|
||||
"custom": "exclude-me",
|
||||
"custom": "include-me"
|
||||
}`)
|
||||
|
||||
func TestDuplicateJWKSetMembersIgnored(t *testing.T) {
|
||||
type CustomSet struct {
|
||||
JsonWebKeySet
|
||||
CustomMember string `json:"custom"`
|
||||
}
|
||||
data := []byte(JWKSetDuplicates)
|
||||
var set CustomSet
|
||||
json.Unmarshal(data, &set)
|
||||
if len(set.Keys) != 1 {
|
||||
t.Error("expected only one key in set")
|
||||
}
|
||||
if set.Keys[0].KeyID != "include-me" {
|
||||
t.Errorf("expected key with kid: \"include-me\", got: %s", set.Keys[0].KeyID)
|
||||
}
|
||||
if set.CustomMember != "include-me" {
|
||||
t.Errorf("expected custom member value: \"include-me\", got: %s", set.CustomMember)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWKSetKey(t *testing.T) {
|
||||
jwk1 := JsonWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
|
||||
jwk2 := JsonWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
|
||||
var set JsonWebKeySet
|
||||
set.Keys = append(set.Keys, jwk1)
|
||||
set.Keys = append(set.Keys, jwk2)
|
||||
k := set.Key("ABCDEFG")
|
||||
if len(k) != 1 {
|
||||
t.Errorf("method should return slice with one key not %d", len(k))
|
||||
}
|
||||
if k[0].KeyID != "ABCDEFG" {
|
||||
t.Error("method should return key with ID ABCDEFG")
|
||||
}
|
||||
}
|
||||
|
|
@ -46,8 +46,12 @@ type JsonWebSignature struct {
|
|||
|
||||
// Signature represents a single signature over the JWS payload and protected header.
|
||||
type Signature struct {
|
||||
Header JoseHeader
|
||||
// Header fields, such as the signature algorithm
|
||||
Header JoseHeader
|
||||
|
||||
// The actual signature value
|
||||
Signature []byte
|
||||
|
||||
protected *rawHeader
|
||||
header *rawHeader
|
||||
original *rawSignatureInfo
|
||||
|
|
@ -102,7 +106,7 @@ func parseSignedFull(input string) (*JsonWebSignature, error) {
|
|||
// sanitized produces a cleaned-up JWS object from the raw JSON.
|
||||
func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
||||
if parsed.Payload == nil {
|
||||
return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
|
||||
return nil, ErrUnprotectedNonce
|
||||
}
|
||||
|
||||
obj := &JsonWebSignature{
|
||||
|
|
@ -121,6 +125,10 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if parsed.Header != nil && parsed.Header.Nonce != "" {
|
||||
return nil, ErrUnprotectedNonce
|
||||
}
|
||||
|
||||
signature.header = parsed.Header
|
||||
signature.Signature = parsed.Signature.bytes()
|
||||
// Make a fake "original" rawSignatureInfo to store the unprocessed
|
||||
|
|
@ -151,6 +159,11 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check that there is not a nonce in the unprotected header
|
||||
if sig.Header != nil && sig.Header.Nonce != "" {
|
||||
return nil, ErrUnprotectedNonce
|
||||
}
|
||||
|
||||
obj.Signatures[i].Signature = sig.Signature.bytes()
|
||||
|
||||
// Copy value of sig
|
||||
|
|
@ -238,20 +251,3 @@ func (obj JsonWebSignature) FullSerialize() string {
|
|||
|
||||
return string(mustSerializeJSON(raw))
|
||||
}
|
||||
|
||||
// MarshalJSON serializes the JWS to JSON.
|
||||
func (obj JsonWebSignature) MarshalJSON() (result []byte, err error) {
|
||||
return []byte(obj.FullSerialize()), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses a JWS from JSON data. (This may also accept a compact
|
||||
// JWS in a string.)
|
||||
func (obj *JsonWebSignature) UnmarshalJSON(data []byte) (err error) {
|
||||
parsedJWS, err := ParseSigned(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*obj = *parsedJWS
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,290 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompactParseJWS(t *testing.T) {
|
||||
// Should parse
|
||||
msg := "eyJhbGciOiJYWVoifQ.cGF5bG9hZA.c2lnbmF0dXJl"
|
||||
_, err := ParseSigned(msg)
|
||||
if err != nil {
|
||||
t.Error("Unable to parse valid message:", err)
|
||||
}
|
||||
|
||||
// Messages that should fail to parse
|
||||
failures := []string{
|
||||
// Not enough parts
|
||||
"eyJhbGciOiJYWVoifQ.cGF5bG9hZA",
|
||||
// Invalid signature
|
||||
"eyJhbGciOiJYWVoifQ.cGF5bG9hZA.////",
|
||||
// Invalid payload
|
||||
"eyJhbGciOiJYWVoifQ.////.c2lnbmF0dXJl",
|
||||
// Invalid header
|
||||
"////.eyJhbGciOiJYWVoifQ.c2lnbmF0dXJl",
|
||||
// Invalid header
|
||||
"cGF5bG9hZA.cGF5bG9hZA.c2lnbmF0dXJl",
|
||||
}
|
||||
|
||||
for i := range failures {
|
||||
_, err = ParseSigned(failures[i])
|
||||
if err == nil {
|
||||
t.Error("Able to parse invalid message")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullParseJWS(t *testing.T) {
|
||||
// Messages that should succeed to parse
|
||||
successes := []string{
|
||||
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"},{\"protected\":\"e30\",\"signature\":\"CUJD\"}]}",
|
||||
}
|
||||
|
||||
for i := range successes {
|
||||
_, err := ParseSigned(successes[i])
|
||||
if err != nil {
|
||||
t.Error("Unble to parse valid message", err, successes[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Messages that should fail to parse
|
||||
failures := []string{
|
||||
// Empty
|
||||
"{}",
|
||||
// Invalid JSON
|
||||
"{XX",
|
||||
// Invalid protected header
|
||||
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
|
||||
// Invalid protected header
|
||||
"{\"payload\":\"CUJD\",\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}",
|
||||
// Invalid protected header
|
||||
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"###\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
|
||||
// Invalid payload
|
||||
"{\"payload\":\"###\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
|
||||
// Invalid payload
|
||||
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"###\"}]}",
|
||||
}
|
||||
|
||||
for i := range failures {
|
||||
_, err := ParseSigned(failures[i])
|
||||
if err == nil {
|
||||
t.Error("Able to parse invalid message", err, failures[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectUnprotectedJWSNonce(t *testing.T) {
|
||||
// No need to test compact, since that's always protected
|
||||
|
||||
// Flattened JSON
|
||||
input := `{
|
||||
"header": { "nonce": "should-cause-an-error" },
|
||||
"payload": "does-not-matter",
|
||||
"signature": "does-not-matter"
|
||||
}`
|
||||
_, err := ParseSigned(input)
|
||||
if err == nil {
|
||||
t.Error("JWS with an unprotected nonce parsed as valid.")
|
||||
} else if err != ErrUnprotectedNonce {
|
||||
t.Errorf("Improper error for unprotected nonce: %v", err)
|
||||
}
|
||||
|
||||
// Full JSON
|
||||
input = `{
|
||||
"payload": "does-not-matter",
|
||||
"signatures": [{
|
||||
"header": { "nonce": "should-cause-an-error" },
|
||||
"signature": "does-not-matter"
|
||||
}]
|
||||
}`
|
||||
_, err = ParseSigned(input)
|
||||
if err == nil {
|
||||
t.Error("JWS with an unprotected nonce parsed as valid.")
|
||||
} else if err != ErrUnprotectedNonce {
|
||||
t.Errorf("Improper error for unprotected nonce: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyFlattenedWithIncludedUnprotectedKey(t *testing.T) {
|
||||
input := `{
|
||||
"header": {
|
||||
"alg": "RS256",
|
||||
"jwk": {
|
||||
"e": "AQAB",
|
||||
"kty": "RSA",
|
||||
"n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ"
|
||||
}
|
||||
},
|
||||
"payload": "Zm9vCg",
|
||||
"signature": "hRt2eYqBd_MyMRNIh8PEIACoFtmBi7BHTLBaAhpSU6zyDAFdEBaX7us4VB9Vo1afOL03Q8iuoRA0AT4akdV_mQTAQ_jhTcVOAeXPr0tB8b8Q11UPQ0tXJYmU4spAW2SapJIvO50ntUaqU05kZd0qw8-noH1Lja-aNnU-tQII4iYVvlTiRJ5g8_CADsvJqOk6FcHuo2mG643TRnhkAxUtazvHyIHeXMxydMMSrpwUwzMtln4ZJYBNx4QGEq6OhpAD_VSp-w8Lq5HOwGQoNs0bPxH1SGrArt67LFQBfjlVr94E1sn26p4vigXm83nJdNhWAMHHE9iV67xN-r29LT-FjA"
|
||||
}`
|
||||
|
||||
jws, err := ParseSigned(input)
|
||||
if err != nil {
|
||||
t.Error("Unable to parse valid message.")
|
||||
}
|
||||
if len(jws.Signatures) != 1 {
|
||||
t.Error("Too many or too few signatures.")
|
||||
}
|
||||
sig := jws.Signatures[0]
|
||||
if sig.Header.JsonWebKey == nil {
|
||||
t.Error("No JWK in signature header.")
|
||||
}
|
||||
payload, err := jws.Verify(sig.Header.JsonWebKey)
|
||||
if err != nil {
|
||||
t.Error(fmt.Sprintf("Signature did not validate: %v", err))
|
||||
}
|
||||
if string(payload) != "foo\n" {
|
||||
t.Error(fmt.Sprintf("Payload was incorrect: '%s' should have been 'foo\\n'", string(payload)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyFlattenedWithPrivateProtected(t *testing.T) {
|
||||
// The protected field contains a Private Header Parameter name, per
|
||||
// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
|
||||
// Base64-decoded, it's '{"nonce":"8HIepUNFZUa-exKTrXVf4g"}'
|
||||
input := `{"header":{"alg":"RS256","jwk":{"kty":"RSA","n":"7ixeydcbxxppzxrBphrW1atUiEZqTpiHDpI-79olav5XxAgWolHmVsJyxzoZXRxmtED8PF9-EICZWBGdSAL9ZTD0hLUCIsPcpdgT_LqNW3Sh2b2caPL2hbMF7vsXvnCGg9varpnHWuYTyRrCLUF9vM7ES-V3VCYTa7LcCSRm56Gg9r19qar43Z9kIKBBxpgt723v2cC4bmLmoAX2s217ou3uCpCXGLOeV_BesG4--Nl3pso1VhCfO85wEWjmW6lbv7Kg4d7Jdkv5DjDZfJ086fkEAYZVYGRpIgAvJBH3d3yKDCrSByUEud1bWuFjQBmMaeYOrVDXO_mbYg5PwUDMhw","e":"AQAB"}},"protected":"eyJub25jZSI6IjhISWVwVU5GWlVhLWV4S1RyWFZmNGcifQ","payload":"eyJjb250YWN0IjpbIm1haWx0bzpmb29AYmFyLmNvbSJdfQ","signature":"AyvVGMgXsQ1zTdXrZxE_gyO63pQgotL1KbI7gv6Wi8I7NRy0iAOkDAkWcTQT9pcCYApJ04lXfEDZfP5i0XgcFUm_6spxi5mFBZU-NemKcvK9dUiAbXvb4hB3GnaZtZiuVnMQUb_ku4DOaFFKbteA6gOYCnED_x7v0kAPHIYrQnvIa-KZ6pTajbV9348zgh9TL7NgGIIsTcMHd-Jatr4z1LQ0ubGa8tS300hoDhVzfoDQaEetYjCo1drR1RmdEN1SIzXdHOHfubjA3ZZRbrF_AJnNKpRRoIwzu1VayOhRmdy1qVSQZq_tENF4VrQFycEL7DhG7JLoXC4T2p1urwMlsw"}`
|
||||
|
||||
jws, err := ParseSigned(input)
|
||||
if err != nil {
|
||||
t.Error("Unable to parse valid message.")
|
||||
}
|
||||
if len(jws.Signatures) != 1 {
|
||||
t.Error("Too many or too few signatures.")
|
||||
}
|
||||
sig := jws.Signatures[0]
|
||||
if sig.Header.JsonWebKey == nil {
|
||||
t.Error("No JWK in signature header.")
|
||||
}
|
||||
payload, err := jws.Verify(sig.Header.JsonWebKey)
|
||||
if err != nil {
|
||||
t.Error(fmt.Sprintf("Signature did not validate: %v", err))
|
||||
}
|
||||
expected := "{\"contact\":[\"mailto:foo@bar.com\"]}"
|
||||
if string(payload) != expected {
|
||||
t.Error(fmt.Sprintf("Payload was incorrect: '%s' should have been '%s'", string(payload), expected))
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors generated with nimbus-jose-jwt
|
||||
func TestSampleNimbusJWSMessagesRSA(t *testing.T) {
|
||||
rsaPublicKey, err := LoadPublicKey(fromBase64Bytes(`
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
|
||||
91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
|
||||
t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
|
||||
NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
|
||||
CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
|
||||
zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rsaSampleMessages := []string{
|
||||
"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
|
||||
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
|
||||
"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
|
||||
"eyJhbGciOiJQUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.UTtxjsv_6x4CdlAmZfAW6Lun3byMjJbcwRp_OlPH2W4MZaZar7aql052mIB_ddK45O9VUz2aphYVRvKPZY8WHmvlTUU30bk0z_cDJRYB9eIJVMOiRCYj0oNkz1iEZqsP0YgngxwuUDv4Q4A6aJ0Bo5E_rZo3AnrVHMHUjPp_ZRRSBFs30tQma1qQ0ApK4Gxk0XYCYAcxIv99e78vldVRaGzjEZmQeAVZx4tGcqZP20vG1L84nlhSGnOuZ0FhR8UjRFLXuob6M7EqtMRoqPgRYw47EI3fYBdeSivAg98E5S8R7R1NJc7ef-l03RvfUSY0S3_zBq_4PlHK6A-2kHb__w",
|
||||
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
|
||||
"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
|
||||
}
|
||||
|
||||
for _, msg := range rsaSampleMessages {
|
||||
obj, err := ParseSigned(msg)
|
||||
if err != nil {
|
||||
t.Error("unable to parse message", msg, err)
|
||||
continue
|
||||
}
|
||||
payload, err := obj.Verify(rsaPublicKey)
|
||||
if err != nil {
|
||||
t.Error("unable to verify message", msg, err)
|
||||
continue
|
||||
}
|
||||
if string(payload) != "Lorem ipsum dolor sit amet" {
|
||||
t.Error("payload is not what we expected for msg", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors generated with nimbus-jose-jwt
|
||||
func TestSampleNimbusJWSMessagesEC(t *testing.T) {
|
||||
ecPublicKeyP256, err := LoadPublicKey(fromBase64Bytes("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIg62jq6FyL1otEj9Up7S35BUrwGF9TVrAzrrY1rHUKZqYIGEg67u/imjgadVcr7y9Q32I0gB8W8FHqbqt696rA=="))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ecPublicKeyP384, err := LoadPublicKey(fromBase64Bytes("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEPXsVlqCtN2oTY+F+hFZm3M0ldYpb7IeeJM5wYmT0k1RaqzBFDhDMNnYK5Q5x+OyssZrAtHgYDFw02AVJhhng/eHRp7mqmL/vI3wbxJtrLKYldIbBA+9fYBQcKeibjlu5"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ecPublicKeyP521, err := LoadPublicKey(fromBase64Bytes("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAa2w3MMJ5FWD6tSf68G+Wy5jIhWXOD3IA7pE5IC/myQzo1lWcD8KS57SM6nm4POtPcxyLmDhL7FLuh8DKoIZyvtAAdK8+tOQP7XXRlT2bkvzIuazp05It3TAPu00YzTIpKfDlc19Y1lvf7etrbFqhShD92B+hHmhT4ddrdbPCBDW8hvU="))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ecPublicKeys := []interface{}{ecPublicKeyP256, ecPublicKeyP384, ecPublicKeyP521}
|
||||
|
||||
ecSampleMessages := []string{
|
||||
"eyJhbGciOiJFUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.MEWJVlvGRQyzMEGOYm4rwuiwxrX-6LjnlbaRDAuhwmnBm2Gtn7pRpGXRTMFZUXsSGDz2L1p-Hz1qn8j9bFIBtQ",
|
||||
"eyJhbGciOiJFUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.nbdjPnJPYQtVNNdBIx8-KbFKplTxrz-hnW5UNhYUY7SBkwHK4NZnqc2Lv4DXoA0aWHq9eiypgOh1kmyPWGEmqKAHUx0xdIEkBoHk3ZsbmhOQuq2jL_wcMUG6nTWNhLrB",
|
||||
"eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g",
|
||||
}
|
||||
|
||||
for i, msg := range ecSampleMessages {
|
||||
obj, err := ParseSigned(msg)
|
||||
if err != nil {
|
||||
t.Error("unable to parse message", msg, err)
|
||||
continue
|
||||
}
|
||||
payload, err := obj.Verify(ecPublicKeys[i])
|
||||
if err != nil {
|
||||
t.Error("unable to verify message", msg, err)
|
||||
continue
|
||||
}
|
||||
if string(payload) != "Lorem ipsum dolor sit amet" {
|
||||
t.Error("payload is not what we expected for msg", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors generated with nimbus-jose-jwt
|
||||
func TestSampleNimbusJWSMessagesHMAC(t *testing.T) {
|
||||
hmacTestKey := fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D")
|
||||
|
||||
hmacSampleMessages := []string{
|
||||
"eyJhbGciOiJIUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.W5tc_EUhxexcvLYEEOckyyvdb__M5DQIVpg6Nmk1XGM",
|
||||
"eyJhbGciOiJIUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.sBu44lXOJa4Nd10oqOdYH2uz3lxlZ6o32QSGHaoGdPtYTDG5zvSja6N48CXKqdAh",
|
||||
"eyJhbGciOiJIUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.M0yR4tmipsORIix-BitIbxEPGaxPchDfj8UNOpKuhDEfnb7URjGvCKn4nOlyQ1z9mG1FKbwnqR1hOVAWSzAU_w",
|
||||
}
|
||||
|
||||
for _, msg := range hmacSampleMessages {
|
||||
obj, err := ParseSigned(msg)
|
||||
if err != nil {
|
||||
t.Error("unable to parse message", msg, err)
|
||||
continue
|
||||
}
|
||||
payload, err := obj.Verify(hmacTestKey)
|
||||
if err != nil {
|
||||
t.Error("unable to verify message", msg, err)
|
||||
continue
|
||||
}
|
||||
if string(payload) != "Lorem ipsum dolor sit amet" {
|
||||
t.Error("payload is not what we expected for msg", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,9 @@
|
|||
package jose
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// KeyAlgorithm represents a key management algorithm.
|
||||
|
|
@ -53,6 +55,10 @@ var (
|
|||
// trying to compact-serialize an object which can't be represented in
|
||||
// compact form.
|
||||
ErrNotSupported = errors.New("square/go-jose: compact serialization not supported for object")
|
||||
|
||||
// ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a
|
||||
// nonce header parameter was included in an unprotected header object.
|
||||
ErrUnprotectedNonce = errors.New("square/go-jose: Nonce parameter included in unprotected header")
|
||||
)
|
||||
|
||||
// Key management algorithms
|
||||
|
|
@ -84,9 +90,9 @@ const (
|
|||
RS256 = SignatureAlgorithm("RS256") // RSASSA-PKCS-v1.5 using SHA-256
|
||||
RS384 = SignatureAlgorithm("RS384") // RSASSA-PKCS-v1.5 using SHA-384
|
||||
RS512 = SignatureAlgorithm("RS512") // RSASSA-PKCS-v1.5 using SHA-512
|
||||
ES256 = SignatureAlgorithm("ES256") // RCDSA using P-256 and SHA-256
|
||||
ES384 = SignatureAlgorithm("ES384") // RCDSA using P-384 and SHA-384
|
||||
ES512 = SignatureAlgorithm("ES512") // RCDSA using P-521 and SHA-512
|
||||
ES256 = SignatureAlgorithm("ES256") // ECDSA using P-256 and SHA-256
|
||||
ES384 = SignatureAlgorithm("ES384") // ECDSA using P-384 and SHA-384
|
||||
ES512 = SignatureAlgorithm("ES512") // ECDSA using P-521 and SHA-512
|
||||
PS256 = SignatureAlgorithm("PS256") // RSASSA-PSS using SHA256 and MGF1-SHA256
|
||||
PS384 = SignatureAlgorithm("PS384") // RSASSA-PSS using SHA384 and MGF1-SHA384
|
||||
PS512 = SignatureAlgorithm("PS512") // RSASSA-PSS using SHA512 and MGF1-SHA512
|
||||
|
|
@ -128,8 +134,8 @@ type rawHeader struct {
|
|||
type JoseHeader struct {
|
||||
KeyID string
|
||||
JsonWebKey *JsonWebKey
|
||||
Nonce string
|
||||
Algorithm string
|
||||
Nonce string
|
||||
}
|
||||
|
||||
// sanitized produces a cleaned-up header object from the raw JSON.
|
||||
|
|
@ -137,8 +143,8 @@ func (parsed rawHeader) sanitized() JoseHeader {
|
|||
return JoseHeader{
|
||||
KeyID: parsed.Kid,
|
||||
JsonWebKey: parsed.Jwk,
|
||||
Nonce: parsed.Nonce,
|
||||
Algorithm: parsed.Alg,
|
||||
Nonce: parsed.Nonce,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,3 +194,31 @@ func (dst *rawHeader) merge(src *rawHeader) {
|
|||
dst.Nonce = src.Nonce
|
||||
}
|
||||
}
|
||||
|
||||
// Get JOSE name of curve
|
||||
func curveName(crv elliptic.Curve) (string, error) {
|
||||
switch crv {
|
||||
case elliptic.P256():
|
||||
return "P-256", nil
|
||||
case elliptic.P384():
|
||||
return "P-384", nil
|
||||
case elliptic.P521():
|
||||
return "P-521", nil
|
||||
default:
|
||||
return "", fmt.Errorf("square/go-jose: unsupported/unknown elliptic curve")
|
||||
}
|
||||
}
|
||||
|
||||
// Get size of curve in bytes
|
||||
func curveSize(crv elliptic.Curve) int {
|
||||
bits := crv.Params().BitSize
|
||||
|
||||
div := bits / 8
|
||||
mod := bits % 8
|
||||
|
||||
if mod == 0 {
|
||||
return div
|
||||
}
|
||||
|
||||
return div + 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,21 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// NonceSource represents a source of random nonces to go into JWS objects
|
||||
type NonceSource interface {
|
||||
Nonce() (string, error)
|
||||
}
|
||||
|
||||
// Signer represents a signer which takes a payload and produces a signed JWS object.
|
||||
type Signer interface {
|
||||
Sign(payload []byte, nonce string) (*JsonWebSignature, error)
|
||||
Sign(payload []byte) (*JsonWebSignature, error)
|
||||
SetNonceSource(source NonceSource)
|
||||
}
|
||||
|
||||
// MultiSigner represents a signer which supports multiple recipients.
|
||||
type MultiSigner interface {
|
||||
Sign(payload []byte, nonce string) (*JsonWebSignature, error)
|
||||
Sign(payload []byte) (*JsonWebSignature, error)
|
||||
SetNonceSource(source NonceSource)
|
||||
AddRecipient(alg SignatureAlgorithm, signingKey interface{}) error
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +49,8 @@ type payloadVerifier interface {
|
|||
}
|
||||
|
||||
type genericSigner struct {
|
||||
recipients []recipientSigInfo
|
||||
recipients []recipientSigInfo
|
||||
nonceSource NonceSource
|
||||
}
|
||||
|
||||
type recipientSigInfo struct {
|
||||
|
|
@ -123,7 +131,7 @@ func makeRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipientSig
|
|||
}
|
||||
}
|
||||
|
||||
func (ctx *genericSigner) Sign(payload []byte, nonce string) (*JsonWebSignature, error) {
|
||||
func (ctx *genericSigner) Sign(payload []byte) (*JsonWebSignature, error) {
|
||||
obj := &JsonWebSignature{}
|
||||
obj.payload = payload
|
||||
obj.Signatures = make([]Signature, len(ctx.recipients))
|
||||
|
|
@ -138,7 +146,11 @@ func (ctx *genericSigner) Sign(payload []byte, nonce string) (*JsonWebSignature,
|
|||
protected.Kid = recipient.publicKey.KeyID
|
||||
}
|
||||
|
||||
if nonce != "" {
|
||||
if ctx.nonceSource != nil {
|
||||
nonce, err := ctx.nonceSource.Nonce()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("square/go-jose: Error generating nonce: %v", err)
|
||||
}
|
||||
protected.Nonce = nonce
|
||||
}
|
||||
|
||||
|
|
@ -160,11 +172,18 @@ func (ctx *genericSigner) Sign(payload []byte, nonce string) (*JsonWebSignature,
|
|||
return obj, nil
|
||||
}
|
||||
|
||||
// SetNonceSource provides or updates a nonce pool to the first recipients.
|
||||
// After this method is called, the signer will consume one nonce per
|
||||
// signature, returning an error it is unable to get a nonce.
|
||||
func (ctx *genericSigner) SetNonceSource(source NonceSource) {
|
||||
ctx.nonceSource = source
|
||||
}
|
||||
|
||||
// Verify validates the signature on the object and returns the payload.
|
||||
func (obj JsonWebSignature) Verify(verificationKey interface{}) ([]byte, JoseHeader, error) {
|
||||
func (obj JsonWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
|
||||
verifier, err := newVerifier(verificationKey)
|
||||
if err != nil {
|
||||
return nil, JoseHeader{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, signature := range obj.Signatures {
|
||||
|
|
@ -173,13 +192,14 @@ func (obj JsonWebSignature) Verify(verificationKey interface{}) ([]byte, JoseHea
|
|||
// Unsupported crit header
|
||||
continue
|
||||
}
|
||||
|
||||
input := obj.computeAuthData(&signature)
|
||||
alg := SignatureAlgorithm(headers.Alg)
|
||||
err := verifier.verifyPayload(input, signature.Signature, alg)
|
||||
if err == nil {
|
||||
return obj.payload, headers.sanitized(), nil
|
||||
return obj.payload, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, JoseHeader{}, ErrCryptoFailure
|
||||
return nil, ErrCryptoFailure
|
||||
}
|
||||
|
|
|
|||
379
Godeps/_workspace/src/github.com/letsencrypt/go-jose/signing_test.go
generated
vendored
Normal file
379
Godeps/_workspace/src/github.com/letsencrypt/go-jose/signing_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type staticNonceSource string
|
||||
|
||||
func (sns staticNonceSource) Nonce() (string, error) {
|
||||
return string(sns), nil
|
||||
}
|
||||
|
||||
func RoundtripJWS(sigAlg SignatureAlgorithm, serializer func(*JsonWebSignature) (string, error), corrupter func(*JsonWebSignature), signingKey interface{}, verificationKey interface{}, nonce string) error {
|
||||
signer, err := NewSigner(sigAlg, signingKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on new signer: %s", err)
|
||||
}
|
||||
|
||||
if nonce != "" {
|
||||
signer.SetNonceSource(staticNonceSource(nonce))
|
||||
}
|
||||
|
||||
input := []byte("Lorem ipsum dolor sit amet")
|
||||
obj, err := signer.Sign(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on sign: %s", err)
|
||||
}
|
||||
|
||||
msg, err := serializer(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on serialize: %s", err)
|
||||
}
|
||||
|
||||
obj, err = ParseSigned(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on parse: %s", err)
|
||||
}
|
||||
|
||||
// (Maybe) mangle the object
|
||||
corrupter(obj)
|
||||
|
||||
output, err := obj.Verify(verificationKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on verify: %s", err)
|
||||
}
|
||||
|
||||
// Check that verify works with embedded keys (if present)
|
||||
for i, sig := range obj.Signatures {
|
||||
if sig.Header.JsonWebKey != nil {
|
||||
_, err = obj.Verify(sig.Header.JsonWebKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on verify with embedded key %d: %s", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the nonce correctly round-tripped (if present)
|
||||
if sig.Header.Nonce != nonce {
|
||||
return fmt.Errorf("Incorrect nonce returned: [%s]", sig.Header.Nonce)
|
||||
}
|
||||
}
|
||||
|
||||
if bytes.Compare(output, input) != 0 {
|
||||
return fmt.Errorf("input/output do not match, got '%s', expected '%s'", output, input)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRoundtripsJWS(t *testing.T) {
|
||||
// Test matrix
|
||||
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, HS256, HS384, HS512, ES256, ES384, ES512}
|
||||
|
||||
serializers := []func(*JsonWebSignature) (string, error){
|
||||
func(obj *JsonWebSignature) (string, error) { return obj.CompactSerialize() },
|
||||
func(obj *JsonWebSignature) (string, error) { return obj.FullSerialize(), nil },
|
||||
}
|
||||
|
||||
corrupter := func(obj *JsonWebSignature) {}
|
||||
|
||||
for _, alg := range sigAlgs {
|
||||
signingKey, verificationKey := GenerateSigningTestKey(alg)
|
||||
|
||||
for i, serializer := range serializers {
|
||||
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
|
||||
if err != nil {
|
||||
t.Error(err, alg, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundtripsJWSCorruptSignature(t *testing.T) {
|
||||
// Test matrix
|
||||
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, HS256, HS384, HS512, ES256, ES384, ES512}
|
||||
|
||||
serializers := []func(*JsonWebSignature) (string, error){
|
||||
func(obj *JsonWebSignature) (string, error) { return obj.CompactSerialize() },
|
||||
func(obj *JsonWebSignature) (string, error) { return obj.FullSerialize(), nil },
|
||||
}
|
||||
|
||||
corrupters := []func(*JsonWebSignature){
|
||||
func(obj *JsonWebSignature) {
|
||||
// Changes bytes in signature
|
||||
obj.Signatures[0].Signature[10]++
|
||||
},
|
||||
func(obj *JsonWebSignature) {
|
||||
// Set totally invalid signature
|
||||
obj.Signatures[0].Signature = []byte("###")
|
||||
},
|
||||
}
|
||||
|
||||
// Test all different configurations
|
||||
for _, alg := range sigAlgs {
|
||||
signingKey, verificationKey := GenerateSigningTestKey(alg)
|
||||
|
||||
for i, serializer := range serializers {
|
||||
for j, corrupter := range corrupters {
|
||||
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
|
||||
if err == nil {
|
||||
t.Error("failed to detect corrupt signature", err, alg, i, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignerWithBrokenRand(t *testing.T) {
|
||||
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512}
|
||||
|
||||
serializer := func(obj *JsonWebSignature) (string, error) { return obj.CompactSerialize() }
|
||||
corrupter := func(obj *JsonWebSignature) {}
|
||||
|
||||
// Break rand reader
|
||||
readers := []func() io.Reader{
|
||||
// Totally broken
|
||||
func() io.Reader { return bytes.NewReader([]byte{}) },
|
||||
// Not enough bytes
|
||||
func() io.Reader { return io.LimitReader(rand.Reader, 20) },
|
||||
}
|
||||
|
||||
defer resetRandReader()
|
||||
|
||||
for _, alg := range sigAlgs {
|
||||
signingKey, verificationKey := GenerateSigningTestKey(alg)
|
||||
for i, getReader := range readers {
|
||||
randReader = getReader()
|
||||
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
|
||||
if err == nil {
|
||||
t.Error("signer should fail if rand is broken", alg, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWSInvalidKey(t *testing.T) {
|
||||
signingKey0, verificationKey0 := GenerateSigningTestKey(RS256)
|
||||
_, verificationKey1 := GenerateSigningTestKey(ES256)
|
||||
|
||||
signer, err := NewSigner(RS256, signingKey0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
input := []byte("Lorem ipsum dolor sit amet")
|
||||
obj, err := signer.Sign(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Must work with correct key
|
||||
_, err = obj.Verify(verificationKey0)
|
||||
if err != nil {
|
||||
t.Error("error on verify", err)
|
||||
}
|
||||
|
||||
// Must not work with incorrect key
|
||||
_, err = obj.Verify(verificationKey1)
|
||||
if err == nil {
|
||||
t.Error("verification should fail with incorrect key")
|
||||
}
|
||||
|
||||
// Must not work with invalid key
|
||||
_, err = obj.Verify("")
|
||||
if err == nil {
|
||||
t.Error("verification should fail with incorrect key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRecipientJWS(t *testing.T) {
|
||||
signer := NewMultiSigner()
|
||||
|
||||
sharedKey := []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
}
|
||||
|
||||
signer.AddRecipient(RS256, rsaTestKey)
|
||||
signer.AddRecipient(HS384, sharedKey)
|
||||
|
||||
input := []byte("Lorem ipsum dolor sit amet")
|
||||
obj, err := signer.Sign(input)
|
||||
if err != nil {
|
||||
t.Error("error on sign: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = obj.CompactSerialize()
|
||||
if err == nil {
|
||||
t.Error("message with multiple recipient was compact serialized")
|
||||
}
|
||||
|
||||
msg := obj.FullSerialize()
|
||||
|
||||
obj, err = ParseSigned(msg)
|
||||
if err != nil {
|
||||
t.Error("error on parse: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
output, err := obj.Verify(&rsaTestKey.PublicKey)
|
||||
if err != nil {
|
||||
t.Error("error on verify: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(output, input) != 0 {
|
||||
t.Error("input/output do not match", output, input)
|
||||
return
|
||||
}
|
||||
|
||||
output, err = obj.Verify(sharedKey)
|
||||
if err != nil {
|
||||
t.Error("error on verify: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(output, input) != 0 {
|
||||
t.Error("input/output do not match", output, input)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateSigningTestKey(sigAlg SignatureAlgorithm) (sig, ver interface{}) {
|
||||
switch sigAlg {
|
||||
case RS256, RS384, RS512, PS256, PS384, PS512:
|
||||
sig = rsaTestKey
|
||||
ver = &rsaTestKey.PublicKey
|
||||
case HS256, HS384, HS512:
|
||||
sig, _, _ = randomKeyGenerator{size: 16}.genKey()
|
||||
ver = sig
|
||||
case ES256:
|
||||
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
sig = key
|
||||
ver = &key.PublicKey
|
||||
case ES384:
|
||||
key, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
sig = key
|
||||
ver = &key.PublicKey
|
||||
case ES512:
|
||||
key, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
sig = key
|
||||
ver = &key.PublicKey
|
||||
default:
|
||||
panic("Must update test case")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestInvalidSignerAlg(t *testing.T) {
|
||||
_, err := NewSigner("XYZ", nil)
|
||||
if err == nil {
|
||||
t.Error("should not accept invalid algorithm")
|
||||
}
|
||||
|
||||
_, err = NewSigner("XYZ", []byte{})
|
||||
if err == nil {
|
||||
t.Error("should not accept invalid algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidJWS(t *testing.T) {
|
||||
signer, err := NewSigner(PS256, rsaTestKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
obj, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
|
||||
obj.Signatures[0].header = &rawHeader{
|
||||
Crit: []string{"TEST"},
|
||||
}
|
||||
|
||||
_, err = obj.Verify(&rsaTestKey.PublicKey)
|
||||
if err == nil {
|
||||
t.Error("should not verify message with unknown crit header")
|
||||
}
|
||||
|
||||
// Try without alg header
|
||||
obj.Signatures[0].protected = &rawHeader{}
|
||||
obj.Signatures[0].header = &rawHeader{}
|
||||
|
||||
_, err = obj.Verify(&rsaTestKey.PublicKey)
|
||||
if err == nil {
|
||||
t.Error("should not verify message with missing headers")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignerKid(t *testing.T) {
|
||||
kid := "DEADBEEF"
|
||||
payload := []byte("Lorem ipsum dolor sit amet")
|
||||
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Error("problem generating test signing key", err)
|
||||
}
|
||||
|
||||
basejwk := JsonWebKey{Key: key}
|
||||
jsonbar, err := basejwk.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Error("problem marshalling base JWK", err)
|
||||
}
|
||||
|
||||
var jsonmsi map[string]interface{}
|
||||
err = json.Unmarshal(jsonbar, &jsonmsi)
|
||||
if err != nil {
|
||||
t.Error("problem unmarshalling base JWK", err)
|
||||
}
|
||||
jsonmsi["kid"] = kid
|
||||
jsonbar2, err := json.Marshal(jsonmsi)
|
||||
if err != nil {
|
||||
t.Error("problem marshalling kided JWK", err)
|
||||
}
|
||||
|
||||
var jwk JsonWebKey
|
||||
err = jwk.UnmarshalJSON(jsonbar2)
|
||||
if err != nil {
|
||||
t.Error("problem unmarshalling kided JWK", err)
|
||||
}
|
||||
|
||||
signer, err := NewSigner(ES256, &jwk)
|
||||
if err != nil {
|
||||
t.Error("problem creating signer", err)
|
||||
}
|
||||
signed, err := signer.Sign(payload)
|
||||
|
||||
serialized := signed.FullSerialize()
|
||||
|
||||
parsed, err := ParseSigned(serialized)
|
||||
if err != nil {
|
||||
t.Error("problem parsing signed object", err)
|
||||
}
|
||||
|
||||
if parsed.Signatures[0].Header.KeyID != kid {
|
||||
t.Error("KeyID did not survive trip")
|
||||
}
|
||||
}
|
||||
131
Godeps/_workspace/src/github.com/letsencrypt/go-jose/symmetric_test.go
generated
vendored
Normal file
131
Godeps/_workspace/src/github.com/letsencrypt/go-jose/symmetric_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInvalidSymmetricAlgorithms(t *testing.T) {
|
||||
_, err := newSymmetricRecipient("XYZ", []byte{})
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should not accept invalid algorithm")
|
||||
}
|
||||
|
||||
enc := &symmetricKeyCipher{}
|
||||
_, err = enc.encryptKey([]byte{}, "XYZ")
|
||||
if err != ErrUnsupportedAlgorithm {
|
||||
t.Error("should not accept invalid algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAeadErrors(t *testing.T) {
|
||||
aead := &aeadContentCipher{
|
||||
keyBytes: 16,
|
||||
authtagBytes: 16,
|
||||
getAead: func(key []byte) (cipher.AEAD, error) {
|
||||
return nil, ErrCryptoFailure
|
||||
},
|
||||
}
|
||||
|
||||
parts, err := aead.encrypt([]byte{}, []byte{}, []byte{})
|
||||
if err != ErrCryptoFailure {
|
||||
t.Error("should handle aead failure")
|
||||
}
|
||||
|
||||
_, err = aead.decrypt([]byte{}, []byte{}, parts)
|
||||
if err != ErrCryptoFailure {
|
||||
t.Error("should handle aead failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidKey(t *testing.T) {
|
||||
gcm := newAESGCM(16).(*aeadContentCipher)
|
||||
_, err := gcm.getAead([]byte{})
|
||||
if err == nil {
|
||||
t.Error("should not accept invalid key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticKeyGen(t *testing.T) {
|
||||
key := make([]byte, 32)
|
||||
io.ReadFull(rand.Reader, key)
|
||||
|
||||
gen := &staticKeyGenerator{key: key}
|
||||
if gen.keySize() != len(key) {
|
||||
t.Error("static key generator reports incorrect size")
|
||||
}
|
||||
|
||||
generated, _, err := gen.genKey()
|
||||
if err != nil {
|
||||
t.Error("static key generator should always succeed", err)
|
||||
}
|
||||
if !bytes.Equal(generated, key) {
|
||||
t.Error("static key generator returns different data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVectorsAESGCM(t *testing.T) {
|
||||
// Source: http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-29#appendix-A.1
|
||||
plaintext := []byte{
|
||||
84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
|
||||
111, 102, 32, 105, 110, 116, 101, 108, 108, 105, 103, 101, 110, 99,
|
||||
101, 32, 105, 115, 32, 110, 111, 116, 32, 107, 110, 111, 119, 108,
|
||||
101, 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105,
|
||||
110, 97, 116, 105, 111, 110, 46}
|
||||
|
||||
aad := []byte{
|
||||
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
|
||||
116, 84, 48, 70, 70, 85, 67, 73, 115, 73, 109, 86, 117, 89, 121, 73,
|
||||
54, 73, 107, 69, 121, 78, 84, 90, 72, 81, 48, 48, 105, 102, 81}
|
||||
|
||||
expectedCiphertext := []byte{
|
||||
229, 236, 166, 241, 53, 191, 115, 196, 174, 43, 73, 109, 39, 122,
|
||||
233, 96, 140, 206, 120, 52, 51, 237, 48, 11, 190, 219, 186, 80, 111,
|
||||
104, 50, 142, 47, 167, 59, 61, 181, 127, 196, 21, 40, 82, 242, 32,
|
||||
123, 143, 168, 226, 73, 216, 176, 144, 138, 247, 106, 60, 16, 205,
|
||||
160, 109, 64, 63, 192}
|
||||
|
||||
expectedAuthtag := []byte{
|
||||
92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
|
||||
|
||||
// Mock random reader
|
||||
randReader = bytes.NewReader([]byte{
|
||||
177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154,
|
||||
212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122,
|
||||
234, 64, 252, 227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219})
|
||||
defer resetRandReader()
|
||||
|
||||
enc := newAESGCM(32)
|
||||
key, _, _ := randomKeyGenerator{size: 32}.genKey()
|
||||
out, err := enc.encrypt(key, aad, plaintext)
|
||||
if err != nil {
|
||||
t.Error("Unable to encrypt:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes.Compare(out.ciphertext, expectedCiphertext) != 0 {
|
||||
t.Error("Ciphertext did not match")
|
||||
}
|
||||
if bytes.Compare(out.tag, expectedAuthtag) != 0 {
|
||||
t.Error("Auth tag did not match")
|
||||
}
|
||||
}
|
||||
225
Godeps/_workspace/src/github.com/letsencrypt/go-jose/utils_test.go
generated
vendored
Normal file
225
Godeps/_workspace/src/github.com/letsencrypt/go-jose/utils_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jose
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Reset random reader to original value
|
||||
func resetRandReader() {
|
||||
randReader = rand.Reader
|
||||
}
|
||||
|
||||
// Build big int from hex-encoded string. Strips whitespace (for testing).
|
||||
func fromHexInt(base16 string) *big.Int {
|
||||
re := regexp.MustCompile(`\s+`)
|
||||
val, ok := new(big.Int).SetString(re.ReplaceAllString(base16, ""), 16)
|
||||
if !ok {
|
||||
panic("Invalid test data")
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Build big int from base64-encoded string. Strips whitespace (for testing).
|
||||
func fromBase64Int(base64 string) *big.Int {
|
||||
re := regexp.MustCompile(`\s+`)
|
||||
val, err := base64URLDecode(re.ReplaceAllString(base64, ""))
|
||||
if err != nil {
|
||||
panic("Invalid test data")
|
||||
}
|
||||
return new(big.Int).SetBytes(val)
|
||||
}
|
||||
|
||||
// Decode hex-encoded string into byte array. Strips whitespace (for testing).
|
||||
func fromHexBytes(base16 string) []byte {
|
||||
re := regexp.MustCompile(`\s+`)
|
||||
val, err := hex.DecodeString(re.ReplaceAllString(base16, ""))
|
||||
if err != nil {
|
||||
panic("Invalid test data")
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Decode base64-encoded string into byte array. Strips whitespace (for testing).
|
||||
func fromBase64Bytes(b64 string) []byte {
|
||||
re := regexp.MustCompile(`\s+`)
|
||||
val, err := base64.StdEncoding.DecodeString(re.ReplaceAllString(b64, ""))
|
||||
if err != nil {
|
||||
panic("Invalid test data")
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Test vectors below taken from crypto/x509/x509_test.go in the Go std lib.
|
||||
|
||||
var pkixPublicKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VoPN9PKUjKFLMwOge6+
|
||||
wnDi8sbETGIx2FKXGgqtAKpzmem53kRGEQg8WeqRmp12wgp74TGpkEXsGae7RS1k
|
||||
enJCnma4fii+noGH7R0qKgHvPrI2Bwa9hzsH8tHxpyM3qrXslOmD45EH9SxIDUBJ
|
||||
FehNdaPbLP1gFyahKMsdfxFJLUvbUycuZSJ2ZnIgeVxwm4qbSvZInL9Iu4FzuPtg
|
||||
fINKcbbovy1qq4KvPIrXzhbY3PWDc6btxCf3SE0JdE1MCPThntB62/bLMSQ7xdDR
|
||||
FF53oIpvxe/SCOymfWq/LW849Ytv3Xwod0+wzAP8STXG4HSELS4UedPYeHJJJYcZ
|
||||
+QIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
var pkcs1PrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
|
||||
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
|
||||
/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
|
||||
RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
|
||||
EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
|
||||
IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
|
||||
tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
var ecdsaSHA256p384CertPem = `
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICSjCCAdECCQDje/no7mXkVzAKBggqhkjOPQQDAjCBjjELMAkGA1UEBhMCVVMx
|
||||
EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS
|
||||
BgNVBAoMC0dvb2dsZSwgSW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG
|
||||
CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIxMDYxMDM0
|
||||
WhcNMjIwNTE5MDYxMDM0WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
|
||||
b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSwg
|
||||
SW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEGCSqGSIb3DQEJARYUZ29s
|
||||
YW5nLWRldkBnbWFpbC5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARRuzRNIKRK
|
||||
jIktEmXanNmrTR/q/FaHXLhWRZ6nHWe26Fw7Rsrbk+VjGy4vfWtNn7xSFKrOu5ze
|
||||
qxKnmE0h5E480MNgrUiRkaGO2GMJJVmxx20aqkXOk59U8yGA4CghE6MwCgYIKoZI
|
||||
zj0EAwIDZwAwZAIwBZEN8gvmRmfeP/9C1PRLzODIY4JqWub2PLRT4mv9GU+yw3Gr
|
||||
PU9A3CHMdEcdw/MEAjBBO1lId8KOCh9UZunsSMfqXiVurpzmhWd6VYZ/32G+M+Mh
|
||||
3yILeYQzllt/g0rKVRk=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var ecdsaSHA256p384CertDer = fromBase64Bytes(`
|
||||
MIICSjCCAdECCQDje/no7mXkVzAKBggqhkjOPQQDAjCBjjELMAkGA1UEBhMCVVMx
|
||||
EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS
|
||||
BgNVBAoMC0dvb2dsZSwgSW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG
|
||||
CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIxMDYxMDM0
|
||||
WhcNMjIwNTE5MDYxMDM0WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
|
||||
b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSwg
|
||||
SW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEGCSqGSIb3DQEJARYUZ29s
|
||||
YW5nLWRldkBnbWFpbC5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARRuzRNIKRK
|
||||
jIktEmXanNmrTR/q/FaHXLhWRZ6nHWe26Fw7Rsrbk+VjGy4vfWtNn7xSFKrOu5ze
|
||||
qxKnmE0h5E480MNgrUiRkaGO2GMJJVmxx20aqkXOk59U8yGA4CghE6MwCgYIKoZI
|
||||
zj0EAwIDZwAwZAIwBZEN8gvmRmfeP/9C1PRLzODIY4JqWub2PLRT4mv9GU+yw3Gr
|
||||
PU9A3CHMdEcdw/MEAjBBO1lId8KOCh9UZunsSMfqXiVurpzmhWd6VYZ/32G+M+Mh
|
||||
3yILeYQzllt/g0rKVRk=`)
|
||||
|
||||
var pkcs8ECPrivateKey = `
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIHtAgEAMBAGByqGSM49AgEGBSuBBAAjBIHVMIHSAgEBBEHqkl65VsjYDQWIHfgv
|
||||
zQLPa0JZBsaJI16mjiH8k6VA4lgfK/KNldlEsY433X7wIzo43u8OpX7Nv7n8pVRH
|
||||
15XWK6GBiQOBhgAEAfDuikMI4bWsyse7t8iSCmjt9fneW/qStZuIPuVLo7mSJdud
|
||||
Cs3J/x9wOnnhLv1u+0atnq5HKKdL4ff3itJPlhmSAQzByKQ5LTvB7d6fn95GJVK/
|
||||
hNuS5qGBpB7qeMXVFoki0/2RZIOway8/fXjmNYwe4v/XB5LLn4hcTvEUGYcF8M9K
|
||||
-----END PRIVATE KEY-----`
|
||||
|
||||
var ecPrivateKey = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIHcAgEBBEIBv2rdY9mWGD/UgiuXB0LJcUzgaB6TXq/Ra1jrZKBV3IGSacM5QDFu
|
||||
N8yrywiQaTDEqn1zVcLwrnqoQux3gWN1jxugBwYFK4EEACOhgYkDgYYABAFJgaM/
|
||||
2a3+gE6Khm/1PYftqNwAzQ21HSLp27q2lTN+GBFho691ARFRkr9UzlQ8gRnhkTbu
|
||||
yGfASamlHsYlr3Tv+gFc4BY8SU0q8kzpQ0dOHWFk7dfGFmKwhJrSFIIOeRn/LY03
|
||||
XsVFctNDsGhobS2JguQrxhGx8Ll7vQCakV/PEmCQJA==
|
||||
-----END EC PRIVATE KEY-----`
|
||||
|
||||
var ecPrivateKeyDer = fromBase64Bytes(`
|
||||
MIHcAgEBBEIBv2rdY9mWGD/UgiuXB0LJcUzgaB6TXq/Ra1jrZKBV3IGSacM5QDFu
|
||||
N8yrywiQaTDEqn1zVcLwrnqoQux3gWN1jxugBwYFK4EEACOhgYkDgYYABAFJgaM/
|
||||
2a3+gE6Khm/1PYftqNwAzQ21HSLp27q2lTN+GBFho691ARFRkr9UzlQ8gRnhkTbu
|
||||
yGfASamlHsYlr3Tv+gFc4BY8SU0q8kzpQ0dOHWFk7dfGFmKwhJrSFIIOeRn/LY03
|
||||
XsVFctNDsGhobS2JguQrxhGx8Ll7vQCakV/PEmCQJA==`)
|
||||
|
||||
var invalidPemKey = `
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIHcAgEBBEIBv2rdY9mWGD/UgiuXB0LJcUzgaB6TXq/Ra1jrZKBV3IGSacM5QDFu
|
||||
XsVFctNDsGhobS2JguQrxhGx8Ll7vQCakV/PEmCQJA==
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
func TestLoadPublicKey(t *testing.T) {
|
||||
pub, err := LoadPublicKey([]byte(pkixPublicKey))
|
||||
switch pub.(type) {
|
||||
case *rsa.PublicKey:
|
||||
default:
|
||||
t.Error("failed to parse RSA PKIX public key:", err)
|
||||
}
|
||||
|
||||
pub, err = LoadPublicKey([]byte(ecdsaSHA256p384CertPem))
|
||||
switch pub.(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
default:
|
||||
t.Error("failed to parse ECDSA X.509 cert:", err)
|
||||
}
|
||||
|
||||
pub, err = LoadPublicKey([]byte(ecdsaSHA256p384CertDer))
|
||||
switch pub.(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
default:
|
||||
t.Error("failed to parse ECDSA X.509 cert:", err)
|
||||
}
|
||||
|
||||
pub, err = LoadPublicKey([]byte("###"))
|
||||
if err == nil {
|
||||
t.Error("should not parse invalid key")
|
||||
}
|
||||
|
||||
pub, err = LoadPublicKey([]byte(invalidPemKey))
|
||||
if err == nil {
|
||||
t.Error("should not parse invalid key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPrivateKey(t *testing.T) {
|
||||
priv, err := LoadPrivateKey([]byte(pkcs1PrivateKey))
|
||||
switch priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
default:
|
||||
t.Error("failed to parse RSA PKCS1 private key:", err)
|
||||
}
|
||||
|
||||
priv, err = LoadPrivateKey([]byte(pkcs8ECPrivateKey))
|
||||
if _, ok := priv.(*ecdsa.PrivateKey); !ok {
|
||||
t.Error("failed to parse EC PKCS8 private key:", err)
|
||||
}
|
||||
|
||||
priv, err = LoadPrivateKey([]byte(ecPrivateKey))
|
||||
if _, ok := priv.(*ecdsa.PrivateKey); !ok {
|
||||
t.Error("failed to parse EC private key:", err)
|
||||
}
|
||||
|
||||
priv, err = LoadPrivateKey([]byte(ecPrivateKeyDer))
|
||||
if _, ok := priv.(*ecdsa.PrivateKey); !ok {
|
||||
t.Error("failed to parse EC private key:", err)
|
||||
}
|
||||
|
||||
priv, err = LoadPrivateKey([]byte("###"))
|
||||
if err == nil {
|
||||
t.Error("should not parse invalid key")
|
||||
}
|
||||
|
||||
priv, err = LoadPrivateKey([]byte(invalidPemKey))
|
||||
if err == nil {
|
||||
t.Error("should not parse invalid key")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5rc1
|
||||
- 1.5
|
||||
script:
|
||||
- go test -short -bench=.
|
||||
- go test -race -v -bench=.
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ If there is stuff you should know as a DNS programmer there isn't a convenience
|
|||
function for it. Server side and client side programming is supported, i.e. you
|
||||
can build servers and resolvers with it.
|
||||
|
||||
If you like this, you may also be interested in:
|
||||
|
||||
* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver.
|
||||
We try to keep the "master" branch as sane as possible and at the bleeding edge
|
||||
of standards, avoiding breaking changes wherever reasonable. We support the last
|
||||
two versions of Go, currently: 1.4 and 1.5.
|
||||
|
||||
# Goals
|
||||
|
||||
|
|
@ -40,6 +40,12 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* https://mesosphere.github.io/mesos-dns/
|
||||
* https://pulse.turbobytes.com/
|
||||
* https://play.google.com/store/apps/details?id=com.turbobytes.dig
|
||||
* https://github.com/fcambus/statzone
|
||||
* https://github.com/benschw/dns-clb-go
|
||||
* https://github.com/corny/dnscheck for http://public-dns.tk/
|
||||
* https://namesmith.io
|
||||
* https://github.com/miekg/unbound
|
||||
* https://github.com/miekg/exdns
|
||||
|
||||
Send pull request if you want to be listed here.
|
||||
|
||||
|
|
@ -121,6 +127,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||
* 6605 - ECDSA
|
||||
* 6725 - IANA Registry Update
|
||||
* 6742 - ILNP DNS
|
||||
* 6840 - Clarifications and Implementation Notes for DNS Security
|
||||
* 6844 - CAA record
|
||||
* 6891 - EDNS0 update
|
||||
* 6895 - DNS IANA considerations
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ type Client struct {
|
|||
//
|
||||
// co := &dns.Conn{Conn: c} // c is your net.Conn
|
||||
// co.WriteMsg(m)
|
||||
// in, err := co.ReadMsg()
|
||||
// in, err := co.ReadMsg()
|
||||
// co.Close()
|
||||
//
|
||||
func Exchange(m *Msg, a string) (r *Msg, err error) {
|
||||
|
|
@ -53,8 +53,6 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
|
|||
}
|
||||
|
||||
defer co.Close()
|
||||
co.SetReadDeadline(time.Now().Add(dnsTimeout))
|
||||
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
|
||||
|
||||
opt := m.IsEdns0()
|
||||
// If EDNS0 is used use that for size.
|
||||
|
|
@ -62,9 +60,12 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
|
|||
co.UDPSize = opt.UDPSize()
|
||||
}
|
||||
|
||||
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
|
||||
if err = co.WriteMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
co.SetReadDeadline(time.Now().Add(dnsTimeout))
|
||||
r, err = co.ReadMsg()
|
||||
if err == nil && r.Id != m.Id {
|
||||
err = ErrId
|
||||
|
|
@ -171,13 +172,13 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
|||
co.UDPSize = c.UDPSize
|
||||
}
|
||||
|
||||
co.SetReadDeadline(time.Now().Add(c.readTimeout()))
|
||||
co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
|
||||
|
||||
co.TsigSecret = c.TsigSecret
|
||||
co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
|
||||
if err = co.WriteMsg(m); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
co.SetReadDeadline(time.Now().Add(c.readTimeout()))
|
||||
r, err = co.ReadMsg()
|
||||
if err == nil && r.Id != m.Id {
|
||||
err = ErrId
|
||||
|
|
@ -196,6 +197,12 @@ func (co *Conn) ReadMsg() (*Msg, error) {
|
|||
|
||||
m := new(Msg)
|
||||
if err := m.Unpack(p); err != nil {
|
||||
// If ErrTruncated was returned, we still want to allow the user to use
|
||||
// the message, but naively they can just check err if they don't want
|
||||
// to use a truncated message
|
||||
if err == ErrTruncated {
|
||||
return m, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if t := m.IsTsig(); t != nil {
|
||||
|
|
|
|||
|
|
@ -1,286 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestClientSync(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
c := new(Client)
|
||||
r, _, err := c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
// And now with plain Exchange().
|
||||
r, err = Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
if r == nil || r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientSyncBadId(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServerBadId)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
c := new(Client)
|
||||
if _, _, err := c.Exchange(m, addrstr); err != ErrId {
|
||||
t.Errorf("did not find a bad Id")
|
||||
}
|
||||
// And now with plain Exchange().
|
||||
if _, err := Exchange(m, addrstr); err != ErrId {
|
||||
t.Errorf("did not find a bad Id")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientEDNS0(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeDNSKEY)
|
||||
|
||||
m.SetEdns0(2048, true)
|
||||
|
||||
c := new(Client)
|
||||
r, _, err := c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
}
|
||||
|
||||
// Validates the transmission and parsing of local EDNS0 options.
|
||||
func TestClientEDNS0Local(t *testing.T) {
|
||||
|
||||
optStr1 := "1979:0x0707"
|
||||
optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"
|
||||
|
||||
handler := func(w ResponseWriter, req *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetReply(req)
|
||||
|
||||
m.Extra = make([]RR, 1, 2)
|
||||
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}
|
||||
|
||||
// If the local options are what we expect, then reflect them back.
|
||||
ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
|
||||
ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
|
||||
if ec1 == optStr1 && ec2 == optStr2 {
|
||||
m.Extra = append(m.Extra, req.Extra[0])
|
||||
}
|
||||
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
HandleFunc("miek.nl.", handler)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %s", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeTXT)
|
||||
|
||||
// Add two local edns options to the query.
|
||||
ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
|
||||
ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
|
||||
o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
|
||||
m.Extra = append(m.Extra, o)
|
||||
|
||||
c := new(Client)
|
||||
r, _, e := c.Exchange(m, addrstr)
|
||||
if e != nil {
|
||||
t.Logf("failed to exchange: %s", e.Error())
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Log("failed to get a valid answer")
|
||||
t.Fail()
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
|
||||
txt := r.Extra[0].(*TXT).Txt[0]
|
||||
if txt != "Hello local edns" {
|
||||
t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Validate the local options in the reply.
|
||||
got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
|
||||
if got != optStr1 {
|
||||
t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
|
||||
t.Fail()
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
|
||||
got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
|
||||
if got != optStr2 {
|
||||
t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
|
||||
t.Fail()
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSingleSingleInflight(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeDNSKEY)
|
||||
|
||||
c := new(Client)
|
||||
c.SingleInflight = true
|
||||
nr := 10
|
||||
ch := make(chan time.Duration)
|
||||
for i := 0; i < nr; i++ {
|
||||
go func() {
|
||||
_, rtt, _ := c.Exchange(m, addrstr)
|
||||
ch <- rtt
|
||||
}()
|
||||
}
|
||||
i := 0
|
||||
var first time.Duration
|
||||
// With inflight *all* rtt are identical, and by doing actual lookups
|
||||
// the changes that this is a coincidence is small.
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case rtt := <-ch:
|
||||
if i == 0 {
|
||||
first = rtt
|
||||
} else {
|
||||
if first != rtt {
|
||||
t.Errorf("all rtts should be equal. got %d want %d", rtt, first)
|
||||
}
|
||||
}
|
||||
i++
|
||||
if i == 10 {
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG.
|
||||
func ExampleUpdateLeaseTSIG(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.SetUpdate("t.local.ip6.io.")
|
||||
rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
|
||||
rrs := make([]RR, 1)
|
||||
rrs[0] = rr
|
||||
m.Insert(rrs)
|
||||
|
||||
leaseRr := new(OPT)
|
||||
leaseRr.Hdr.Name = "."
|
||||
leaseRr.Hdr.Rrtype = TypeOPT
|
||||
e := new(EDNS0_UL)
|
||||
e.Code = EDNS0UL
|
||||
e.Lease = 120
|
||||
leaseRr.Option = append(leaseRr.Option, e)
|
||||
m.Extra = append(m.Extra, leaseRr)
|
||||
|
||||
c := new(Client)
|
||||
m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
|
||||
c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}
|
||||
|
||||
_, _, err := c.Exchange(m, "127.0.0.1:53")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientConn(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
// This uses TCP just to make it slightly different than TestClientSync
|
||||
s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
cn, err := Dial("tcp", addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to dial %s: %v", addrstr, err)
|
||||
}
|
||||
|
||||
err = cn.WriteMsg(m)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
r, err := cn.ReadMsg()
|
||||
if r == nil || r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
|
||||
err = cn.WriteMsg(m)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
h := new(Header)
|
||||
buf, err := cn.ReadMsgHeader(h)
|
||||
if buf == nil {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
if int(h.Bits&0xF) != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r)
|
||||
}
|
||||
if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 {
|
||||
t.Errorf("expected to have question and additional in response; got something else: %+v", h)
|
||||
}
|
||||
if err = r.Unpack(buf); err != nil {
|
||||
t.Errorf("unable to unpack message fully: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const normal string = `
|
||||
# Comment
|
||||
domain somedomain.com
|
||||
nameserver 10.28.10.2
|
||||
nameserver 11.28.10.1
|
||||
`
|
||||
|
||||
const missingNewline string = `
|
||||
domain somedomain.com
|
||||
nameserver 10.28.10.2
|
||||
nameserver 11.28.10.1` // <- NOTE: NO newline.
|
||||
|
||||
func testConfig(t *testing.T, data string) {
|
||||
tempDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("TempDir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
path := filepath.Join(tempDir, "resolv.conf")
|
||||
if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
cc, err := ClientConfigFromFile(path)
|
||||
if err != nil {
|
||||
t.Errorf("error parsing resolv.conf: %v", err)
|
||||
}
|
||||
if l := len(cc.Servers); l != 2 {
|
||||
t.Errorf("incorrect number of nameservers detected: %d", l)
|
||||
}
|
||||
if l := len(cc.Search); l != 1 {
|
||||
t.Errorf("domain directive not parsed correctly: %v", cc.Search)
|
||||
} else {
|
||||
if cc.Search[0] != "somedomain.com" {
|
||||
t.Errorf("domain is unexpected: %v", cc.Search[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNameserver(t *testing.T) {
|
||||
testConfig(t, normal)
|
||||
}
|
||||
|
||||
func TestMissingFinalNewLine(t *testing.T) {
|
||||
testConfig(t, missingNewline)
|
||||
}
|
||||
|
|
@ -150,11 +150,14 @@ func (dns *Msg) IsEdns0() *OPT {
|
|||
return nil
|
||||
}
|
||||
|
||||
// IsDomainName checks if s is a valid domainname, it returns
|
||||
// the number of labels and true, when a domain name is valid.
|
||||
// Note that non fully qualified domain name is considered valid, in this case the
|
||||
// last label is counted in the number of labels.
|
||||
// When false is returned the number of labels is not defined.
|
||||
// IsDomainName checks if s is a valid domain name, it returns the number of
|
||||
// labels and true, when a domain name is valid. Note that non fully qualified
|
||||
// domain name is considered valid, in this case the last label is counted in
|
||||
// the number of labels. When false is returned the number of labels is not
|
||||
// defined. Also note that this function is extremely liberal; almost any
|
||||
// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
|
||||
// label fits in 63 characters, but there is no length check for the entire
|
||||
// string s. I.e. a domain name longer than 255 characters is considered valid.
|
||||
func IsDomainName(s string) (labels int, ok bool) {
|
||||
_, labels, err := packDomainName(s, nil, 0, nil, false)
|
||||
return labels, err == nil
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ type RR interface {
|
|||
len() int
|
||||
}
|
||||
|
||||
// DNS resource records.
|
||||
// There are many types of RRs,
|
||||
// but they all share the same header.
|
||||
// RR_Header is the header all DNS resource records share.
|
||||
type RR_Header struct {
|
||||
Name string `dns:"cdomain-name"`
|
||||
Rrtype uint16
|
||||
|
|
|
|||
|
|
@ -1,578 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPackUnpack(t *testing.T) {
|
||||
out := new(Msg)
|
||||
out.Answer = make([]RR, 1)
|
||||
key := new(DNSKEY)
|
||||
key = &DNSKEY{Flags: 257, Protocol: 3, Algorithm: RSASHA1}
|
||||
key.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 3600}
|
||||
key.PublicKey = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
|
||||
|
||||
out.Answer[0] = key
|
||||
msg, err := out.Pack()
|
||||
if err != nil {
|
||||
t.Error("failed to pack msg with DNSKEY")
|
||||
}
|
||||
in := new(Msg)
|
||||
if in.Unpack(msg) != nil {
|
||||
t.Error("failed to unpack msg with DNSKEY")
|
||||
}
|
||||
|
||||
sig := new(RRSIG)
|
||||
sig = &RRSIG{TypeCovered: TypeDNSKEY, Algorithm: RSASHA1, Labels: 2,
|
||||
OrigTtl: 3600, Expiration: 4000, Inception: 4000, KeyTag: 34641, SignerName: "miek.nl.",
|
||||
Signature: "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"}
|
||||
sig.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeRRSIG, Class: ClassINET, Ttl: 3600}
|
||||
|
||||
out.Answer[0] = sig
|
||||
msg, err = out.Pack()
|
||||
if err != nil {
|
||||
t.Error("failed to pack msg with RRSIG")
|
||||
}
|
||||
|
||||
if in.Unpack(msg) != nil {
|
||||
t.Error("failed to unpack msg with RRSIG")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackUnpack2(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Answer = make([]RR, 1)
|
||||
dom := "miek.nl."
|
||||
rr := new(A)
|
||||
rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0}
|
||||
rr.A = net.IPv4(127, 0, 0, 1)
|
||||
|
||||
x := new(TXT)
|
||||
x.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
|
||||
x.Txt = []string{"heelalaollo"}
|
||||
|
||||
m.Extra[0] = x
|
||||
m.Answer[0] = rr
|
||||
_, err := m.Pack()
|
||||
if err != nil {
|
||||
t.Error("Packing failed: ", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackUnpack3(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.Extra = make([]RR, 2)
|
||||
m.Answer = make([]RR, 1)
|
||||
dom := "miek.nl."
|
||||
rr := new(A)
|
||||
rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0}
|
||||
rr.A = net.IPv4(127, 0, 0, 1)
|
||||
|
||||
x1 := new(TXT)
|
||||
x1.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
|
||||
x1.Txt = []string{}
|
||||
|
||||
x2 := new(TXT)
|
||||
x2.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
|
||||
x2.Txt = []string{"heelalaollo"}
|
||||
|
||||
m.Extra[0] = x1
|
||||
m.Extra[1] = x2
|
||||
m.Answer[0] = rr
|
||||
b, err := m.Pack()
|
||||
if err != nil {
|
||||
t.Error("packing failed: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
var unpackMsg Msg
|
||||
err = unpackMsg.Unpack(b)
|
||||
if err != nil {
|
||||
t.Error("unpacking failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestBailiwick(t *testing.T) {
|
||||
yes := map[string]string{
|
||||
"miek.nl": "ns.miek.nl",
|
||||
".": "miek.nl",
|
||||
}
|
||||
for parent, child := range yes {
|
||||
if !IsSubDomain(parent, child) {
|
||||
t.Errorf("%s should be child of %s", child, parent)
|
||||
t.Errorf("comparelabels %d", CompareDomainName(parent, child))
|
||||
t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
|
||||
}
|
||||
}
|
||||
no := map[string]string{
|
||||
"www.miek.nl": "ns.miek.nl",
|
||||
"m\\.iek.nl": "ns.miek.nl",
|
||||
"w\\.iek.nl": "w.iek.nl",
|
||||
"p\\\\.iek.nl": "ns.p.iek.nl", // p\\.iek.nl , literal \ in domain name
|
||||
"miek.nl": ".",
|
||||
}
|
||||
for parent, child := range no {
|
||||
if IsSubDomain(parent, child) {
|
||||
t.Errorf("%s should not be child of %s", child, parent)
|
||||
t.Errorf("comparelabels %d", CompareDomainName(parent, child))
|
||||
t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPack(t *testing.T) {
|
||||
rr := []string{"US. 86400 IN NSEC 0-.us. NS SOA RRSIG NSEC DNSKEY TYPE65534"}
|
||||
m := new(Msg)
|
||||
var err error
|
||||
m.Answer = make([]RR, 1)
|
||||
for _, r := range rr {
|
||||
m.Answer[0], err = NewRR(r)
|
||||
if err != nil {
|
||||
t.Errorf("failed to create RR: %v", err)
|
||||
continue
|
||||
}
|
||||
if _, err := m.Pack(); err != nil {
|
||||
t.Errorf("packing failed: %v", err)
|
||||
}
|
||||
}
|
||||
x := new(Msg)
|
||||
ns, _ := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org")
|
||||
ns.(*NS).Ns = "a.ntpns.org"
|
||||
x.Ns = append(m.Ns, ns)
|
||||
x.Ns = append(m.Ns, ns)
|
||||
x.Ns = append(m.Ns, ns)
|
||||
// This crashes due to the fact the a.ntpns.org isn't a FQDN
|
||||
// How to recover() from a remove panic()?
|
||||
if _, err := x.Pack(); err == nil {
|
||||
t.Error("packing should fail")
|
||||
}
|
||||
x.Answer = make([]RR, 1)
|
||||
x.Answer[0], err = NewRR(rr[0])
|
||||
if _, err := x.Pack(); err == nil {
|
||||
t.Error("packing should fail")
|
||||
}
|
||||
x.Question = make([]Question, 1)
|
||||
x.Question[0] = Question{";sd#eddddséâèµââ
â¥âxzztsestxssweewwsssstx@s@Zåµe@cn.pool.ntp.org.", TypeA, ClassINET}
|
||||
if _, err := x.Pack(); err == nil {
|
||||
t.Error("packing should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackNAPTR(t *testing.T) {
|
||||
for _, n := range []string{
|
||||
`apple.com. IN NAPTR 100 50 "se" "SIP+D2U" "" _sip._udp.apple.com.`,
|
||||
`apple.com. IN NAPTR 90 50 "se" "SIP+D2T" "" _sip._tcp.apple.com.`,
|
||||
`apple.com. IN NAPTR 50 50 "se" "SIPS+D2T" "" _sips._tcp.apple.com.`,
|
||||
} {
|
||||
rr, _ := NewRR(n)
|
||||
msg := make([]byte, rr.len())
|
||||
if off, err := PackRR(rr, msg, 0, nil, false); err != nil {
|
||||
t.Errorf("packing failed: %v", err)
|
||||
t.Errorf("length %d, need more than %d", rr.len(), off)
|
||||
} else {
|
||||
t.Logf("buf size needed: %d", off)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompressLength(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl", TypeMX)
|
||||
ul := m.Len()
|
||||
m.Compress = true
|
||||
if ul != m.Len() {
|
||||
t.Fatalf("should be equal")
|
||||
}
|
||||
}
|
||||
|
||||
// Does the predicted length match final packed length?
|
||||
func TestMsgCompressLength(t *testing.T) {
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
msg.Compress = true
|
||||
return msg
|
||||
}
|
||||
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
tests := []*Msg{
|
||||
makeMsg(name1, []RR{rrA}, nil, nil),
|
||||
makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
|
||||
|
||||
for _, msg := range tests {
|
||||
predicted := msg.Len()
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if predicted < len(buf) {
|
||||
t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d",
|
||||
msg.Question[0].Name, len(msg.Answer), predicted, len(buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgLength(t *testing.T) {
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
return msg
|
||||
}
|
||||
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
tests := []*Msg{
|
||||
makeMsg(name1, []RR{rrA}, nil, nil),
|
||||
makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
|
||||
|
||||
for _, msg := range tests {
|
||||
predicted := msg.Len()
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if predicted < len(buf) {
|
||||
t.Errorf("predicted length is wrong: predicted %s (len=%d), actual %d",
|
||||
msg.Question[0].Name, predicted, len(buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgLength2(t *testing.T) {
|
||||
// Serialized replies
|
||||
var testMessages = []string{
|
||||
// google.com. IN A?
|
||||
"064e81800001000b0004000506676f6f676c6503636f6d0000010001c00c00010001000000050004adc22986c00c00010001000000050004adc22987c00c00010001000000050004adc22988c00c00010001000000050004adc22989c00c00010001000000050004adc2298ec00c00010001000000050004adc22980c00c00010001000000050004adc22981c00c00010001000000050004adc22982c00c00010001000000050004adc22983c00c00010001000000050004adc22984c00c00010001000000050004adc22985c00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc0d800010001000000050004d8ef200ac0ea00010001000000050004d8ef220ac0fc00010001000000050004d8ef240ac10e00010001000000050004d8ef260a0000290500000000050000",
|
||||
// amazon.com. IN A? (reply has no EDNS0 record)
|
||||
// TODO(miek): this one is off-by-one, need to find out why
|
||||
//"6de1818000010004000a000806616d617a6f6e03636f6d0000010001c00c000100010000000500044815c2d4c00c000100010000000500044815d7e8c00c00010001000000050004b02062a6c00c00010001000000050004cdfbf236c00c000200010000000500140570646e733408756c747261646e73036f726700c00c000200010000000500150570646e733508756c747261646e7304696e666f00c00c000200010000000500160570646e733608756c747261646e7302636f02756b00c00c00020001000000050014036e7331037033310664796e656374036e657400c00c00020001000000050006036e7332c0cfc00c00020001000000050006036e7333c0cfc00c00020001000000050006036e7334c0cfc00c000200010000000500110570646e733108756c747261646e73c0dac00c000200010000000500080570646e7332c127c00c000200010000000500080570646e7333c06ec0cb00010001000000050004d04e461fc0eb00010001000000050004cc0dfa1fc0fd00010001000000050004d04e471fc10f00010001000000050004cc0dfb1fc12100010001000000050004cc4a6c01c121001c000100000005001020010502f3ff00000000000000000001c13e00010001000000050004cc4a6d01c13e001c0001000000050010261000a1101400000000000000000001",
|
||||
// yahoo.com. IN A?
|
||||
"fc2d81800001000300070008057961686f6f03636f6d0000010001c00c00010001000000050004628afd6dc00c00010001000000050004628bb718c00c00010001000000050004cebe242dc00c00020001000000050006036e7336c00cc00c00020001000000050006036e7338c00cc00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7335c00cc07b0001000100000005000444b48310c08d00010001000000050004448eff10c09f00010001000000050004cb54dd35c0b100010001000000050004628a0b9dc0c30001000100000005000477a0f77cc05700010001000000050004ca2bdfaac06900010001000000050004caa568160000290500000000050000",
|
||||
// microsoft.com. IN A?
|
||||
"f4368180000100020005000b096d6963726f736f667403636f6d0000010001c00c0001000100000005000440040b25c00c0001000100000005000441373ac9c00c0002000100000005000e036e7331046d736674036e657400c00c00020001000000050006036e7332c04fc00c00020001000000050006036e7333c04fc00c00020001000000050006036e7334c04fc00c00020001000000050006036e7335c04fc04b000100010000000500044137253ec04b001c00010000000500102a010111200500000000000000010001c0650001000100000005000440043badc065001c00010000000500102a010111200600060000000000010001c07700010001000000050004d5c7b435c077001c00010000000500102a010111202000000000000000010001c08900010001000000050004cf2e4bfec089001c00010000000500102404f800200300000000000000010001c09b000100010000000500044137e28cc09b001c00010000000500102a010111200f000100000000000100010000290500000000050000",
|
||||
// google.com. IN MX?
|
||||
"724b8180000100050004000b06676f6f676c6503636f6d00000f0001c00c000f000100000005000c000a056173706d78016cc00cc00c000f0001000000050009001404616c7431c02ac00c000f0001000000050009001e04616c7432c02ac00c000f0001000000050009002804616c7433c02ac00c000f0001000000050009003204616c7434c02ac00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7331c00cc02a00010001000000050004adc2421bc02a001c00010000000500102a00145040080c01000000000000001bc04200010001000000050004adc2461bc05700010001000000050004adc2451bc06c000100010000000500044a7d8f1bc081000100010000000500044a7d191bc0ca00010001000000050004d8ef200ac09400010001000000050004d8ef220ac0a600010001000000050004d8ef240ac0b800010001000000050004d8ef260a0000290500000000050000",
|
||||
// reddit.com. IN A?
|
||||
"12b98180000100080000000c0672656464697403636f6d0000020001c00c0002000100000005000f046175733204616b616d036e657400c00c000200010000000500070475736534c02dc00c000200010000000500070475737733c02dc00c000200010000000500070475737735c02dc00c00020001000000050008056173696131c02dc00c00020001000000050008056173696139c02dc00c00020001000000050008056e73312d31c02dc00c0002000100000005000a076e73312d313935c02dc02800010001000000050004c30a242ec04300010001000000050004451f1d39c05600010001000000050004451f3bc7c0690001000100000005000460073240c07c000100010000000500046007fb81c090000100010000000500047c283484c090001c00010000000500102a0226f0006700000000000000000064c0a400010001000000050004c16c5b01c0a4001c000100000005001026001401000200000000000000000001c0b800010001000000050004c16c5bc3c0b8001c0001000000050010260014010002000000000000000000c30000290500000000050000",
|
||||
}
|
||||
|
||||
for i, hexData := range testMessages {
|
||||
// we won't fail the decoding of the hex
|
||||
input, _ := hex.DecodeString(hexData)
|
||||
m := new(Msg)
|
||||
m.Unpack(input)
|
||||
//println(m.String())
|
||||
m.Compress = true
|
||||
lenComp := m.Len()
|
||||
b, _ := m.Pack()
|
||||
pacComp := len(b)
|
||||
m.Compress = false
|
||||
lenUnComp := m.Len()
|
||||
b, _ = m.Pack()
|
||||
pacUnComp := len(b)
|
||||
if pacComp+1 != lenComp {
|
||||
t.Errorf("msg.Len(compressed)=%d actual=%d for test %d", lenComp, pacComp, i)
|
||||
}
|
||||
if pacUnComp+1 != lenUnComp {
|
||||
t.Errorf("msg.Len(uncompressed)=%d actual=%d for test %d", lenUnComp, pacUnComp, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgLengthCompressionMalformed(t *testing.T) {
|
||||
// SOA with empty hostmaster, which is illegal
|
||||
soa := &SOA{Hdr: RR_Header{Name: ".", Rrtype: TypeSOA, Class: ClassINET, Ttl: 12345},
|
||||
Ns: ".",
|
||||
Mbox: "",
|
||||
Serial: 0,
|
||||
Refresh: 28800,
|
||||
Retry: 7200,
|
||||
Expire: 604800,
|
||||
Minttl: 60}
|
||||
m := new(Msg)
|
||||
m.Compress = true
|
||||
m.Ns = []RR{soa}
|
||||
m.Len() // Should not crash.
|
||||
}
|
||||
|
||||
func BenchmarkMsgLength(b *testing.B) {
|
||||
b.StopTimer()
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
msg.Compress = true
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
msg.Len()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMsgLengthPack(b *testing.B) {
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
msg.Compress = true
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = msg.Pack()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMsgPackBuffer(b *testing.B) {
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
msg.Compress = true
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
buf := make([]byte, 512)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = msg.PackBuffer(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMsgUnpack(b *testing.B) {
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
msg.Compress = true
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
msgBuf, _ := msg.Pack()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = msg.Unpack(msgBuf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPackDomainName(b *testing.B) {
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
buf := make([]byte, len(name1)+1)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = PackDomainName(name1, buf, 0, nil, false)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnpackDomainName(b *testing.B) {
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
buf := make([]byte, len(name1)+1)
|
||||
_, _ = PackDomainName(name1, buf, 0, nil, false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = UnpackDomainName(buf, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnpackDomainNameUnprintable(b *testing.B) {
|
||||
name1 := "\x02\x02\x02\x025\x02\x02\x02\x02.12345678.123."
|
||||
buf := make([]byte, len(name1)+1)
|
||||
_, _ = PackDomainName(name1, buf, 0, nil, false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = UnpackDomainName(buf, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToRFC3597(t *testing.T) {
|
||||
a, _ := NewRR("miek.nl. IN A 10.0.1.1")
|
||||
x := new(RFC3597)
|
||||
x.ToRFC3597(a)
|
||||
if x.String() != `miek.nl. 3600 CLASS1 TYPE1 \# 4 0a000101` {
|
||||
t.Error("string mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoRdataPack(t *testing.T) {
|
||||
data := make([]byte, 1024)
|
||||
for typ, fn := range typeToRR {
|
||||
r := fn()
|
||||
*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
|
||||
_, err := PackRR(r, data, 0, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("failed to pack RR with zero rdata: %s: %v", TypeToString[typ], err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(miek): fix dns buffer too small errors this throws
|
||||
func TestNoRdataUnpack(t *testing.T) {
|
||||
data := make([]byte, 1024)
|
||||
for typ, fn := range typeToRR {
|
||||
if typ == TypeSOA || typ == TypeTSIG || typ == TypeWKS {
|
||||
// SOA, TSIG will not be seen (like this) in dyn. updates?
|
||||
// WKS is an bug, but...deprecated record.
|
||||
continue
|
||||
}
|
||||
r := fn()
|
||||
*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
|
||||
off, err := PackRR(r, data, 0, nil, false)
|
||||
if err != nil {
|
||||
// Should always works, TestNoDataPack should have caught this
|
||||
t.Errorf("failed to pack RR: %v", err)
|
||||
continue
|
||||
}
|
||||
rr, _, err := UnpackRR(data[:off], 0)
|
||||
if err != nil {
|
||||
t.Errorf("failed to unpack RR with zero rdata: %s: %v", TypeToString[typ], err)
|
||||
}
|
||||
t.Log(rr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRdataOverflow(t *testing.T) {
|
||||
rr := new(RFC3597)
|
||||
rr.Hdr.Name = "."
|
||||
rr.Hdr.Class = ClassINET
|
||||
rr.Hdr.Rrtype = 65280
|
||||
rr.Rdata = hex.EncodeToString(make([]byte, 0xFFFF))
|
||||
buf := make([]byte, 0xFFFF*2)
|
||||
if _, err := PackRR(rr, buf, 0, nil, false); err != nil {
|
||||
t.Fatalf("maximum size rrdata pack failed: %v", err)
|
||||
}
|
||||
rr.Rdata += "00"
|
||||
if _, err := PackRR(rr, buf, 0, nil, false); err != ErrRdata {
|
||||
t.Fatalf("oversize rrdata pack didn't return ErrRdata - instead: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
|
||||
rr1 := Copy(rr)
|
||||
if rr.String() != rr1.String() {
|
||||
t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgCopy(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeA)
|
||||
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
m.Answer = []RR{rr}
|
||||
rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
|
||||
m.Ns = []RR{rr}
|
||||
|
||||
m1 := m.Copy()
|
||||
if m.String() != m1.String() {
|
||||
t.Fatalf("Msg.Copy() failed %s != %s", m.String(), m1.String())
|
||||
}
|
||||
|
||||
m1.Answer[0], _ = NewRR("somethingelse.nl. 2311 IN A 127.0.0.1")
|
||||
if m.String() == m1.String() {
|
||||
t.Fatalf("Msg.Copy() failed; change to copy changed template %s", m.String())
|
||||
}
|
||||
|
||||
rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.2")
|
||||
m1.Answer = append(m1.Answer, rr)
|
||||
if m1.Ns[0].String() == m1.Answer[1].String() {
|
||||
t.Fatalf("Msg.Copy() failed; append changed underlying array %s", m1.Ns[0].String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCopy(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeA)
|
||||
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
m.Answer = []RR{rr}
|
||||
rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
|
||||
m.Ns = []RR{rr}
|
||||
rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
m.Extra = []RR{rr}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Copy()
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackIPSECKEY(t *testing.T) {
|
||||
tests := []string{
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
for _, t1 := range tests {
|
||||
rr, _ := NewRR(t1)
|
||||
off, err := PackRR(rr, buf, 0, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("failed to pack IPSECKEY %v: %s", err, t1)
|
||||
continue
|
||||
}
|
||||
|
||||
rr, _, err = UnpackRR(buf[:off], 0)
|
||||
if err != nil {
|
||||
t.Errorf("failed to unpack IPSECKEY %v: %s", err, t1)
|
||||
}
|
||||
t.Log(rr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgPackBuffer(t *testing.T) {
|
||||
var testMessages = []string{
|
||||
// news.ycombinator.com.in.escapemg.com. IN A, response
|
||||
"586285830001000000010000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001c0210006000100000e10002c036e7332c02103646e730b67726f6f7665736861726bc02d77ed50e600002a3000000e1000093a8000000e10",
|
||||
|
||||
// news.ycombinator.com.in.escapemg.com. IN A, question
|
||||
"586201000001000000000000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001",
|
||||
|
||||
"398781020001000000000000046e6577730b79636f6d62696e61746f7203636f6d0000010001",
|
||||
}
|
||||
|
||||
for i, hexData := range testMessages {
|
||||
// we won't fail the decoding of the hex
|
||||
input, _ := hex.DecodeString(hexData)
|
||||
m := new(Msg)
|
||||
if err := m.Unpack(input); err != nil {
|
||||
t.Errorf("packet %d failed to unpack", i)
|
||||
continue
|
||||
}
|
||||
t.Logf("packet %d %s", i, m.String())
|
||||
}
|
||||
}
|
||||
|
|
@ -6,14 +6,14 @@ import (
|
|||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/md5"
|
||||
_ "crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strings"
|
||||
|
|
@ -42,6 +42,38 @@ const (
|
|||
PRIVATEOID uint8 = 254
|
||||
)
|
||||
|
||||
// Map for algorithm names.
|
||||
var AlgorithmToString = map[uint8]string{
|
||||
RSAMD5: "RSAMD5",
|
||||
DH: "DH",
|
||||
DSA: "DSA",
|
||||
RSASHA1: "RSASHA1",
|
||||
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
|
||||
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
|
||||
RSASHA256: "RSASHA256",
|
||||
RSASHA512: "RSASHA512",
|
||||
ECCGOST: "ECC-GOST",
|
||||
ECDSAP256SHA256: "ECDSAP256SHA256",
|
||||
ECDSAP384SHA384: "ECDSAP384SHA384",
|
||||
INDIRECT: "INDIRECT",
|
||||
PRIVATEDNS: "PRIVATEDNS",
|
||||
PRIVATEOID: "PRIVATEOID",
|
||||
}
|
||||
|
||||
// Map of algorithm strings.
|
||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||
|
||||
// Map of algorithm crypto hashes.
|
||||
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||
RSASHA1: crypto.SHA1,
|
||||
RSASHA1NSEC3SHA1: crypto.SHA1,
|
||||
RSASHA256: crypto.SHA256,
|
||||
ECDSAP256SHA256: crypto.SHA256,
|
||||
ECDSAP384SHA384: crypto.SHA384,
|
||||
RSASHA512: crypto.SHA512,
|
||||
}
|
||||
|
||||
// DNSSEC hashing algorithm codes.
|
||||
const (
|
||||
_ uint8 = iota
|
||||
|
|
@ -52,6 +84,18 @@ const (
|
|||
SHA512 // Experimental
|
||||
)
|
||||
|
||||
// Map for hash names.
|
||||
var HashToString = map[uint8]string{
|
||||
SHA1: "SHA1",
|
||||
SHA256: "SHA256",
|
||||
GOST94: "GOST94",
|
||||
SHA384: "SHA384",
|
||||
SHA512: "SHA512",
|
||||
}
|
||||
|
||||
// Map of hash strings.
|
||||
var StringToHash = reverseInt8(HashToString)
|
||||
|
||||
// DNSKEY flag values.
|
||||
const (
|
||||
SEP = 1
|
||||
|
|
@ -60,7 +104,7 @@ const (
|
|||
)
|
||||
|
||||
// The RRSIG needs to be converted to wireformat with some of
|
||||
// the rdata (the signature) missing. Use this struct to easy
|
||||
// the rdata (the signature) missing. Use this struct to ease
|
||||
// the conversion (and re-use the pack/unpack functions).
|
||||
type rrsigWireFmt struct {
|
||||
TypeCovered uint16
|
||||
|
|
@ -168,24 +212,23 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
|
|||
// digest buffer
|
||||
digest := append(owner, wire...) // another copy
|
||||
|
||||
var hash crypto.Hash
|
||||
switch h {
|
||||
case SHA1:
|
||||
s := sha1.New()
|
||||
io.WriteString(s, string(digest))
|
||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||
hash = crypto.SHA1
|
||||
case SHA256:
|
||||
s := sha256.New()
|
||||
io.WriteString(s, string(digest))
|
||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||
hash = crypto.SHA256
|
||||
case SHA384:
|
||||
s := sha512.New384()
|
||||
io.WriteString(s, string(digest))
|
||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||
case GOST94:
|
||||
/* I have no clue */
|
||||
hash = crypto.SHA384
|
||||
case SHA512:
|
||||
hash = crypto.SHA512
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
s := hash.New()
|
||||
s.Write(digest)
|
||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||
return ds
|
||||
}
|
||||
|
||||
|
|
@ -205,14 +248,13 @@ func (d *DS) ToCDS() *CDS {
|
|||
return c
|
||||
}
|
||||
|
||||
// Sign signs an RRSet. The signature needs to be filled in with
|
||||
// the values: Inception, Expiration, KeyTag, SignerName and Algorithm.
|
||||
// The rest is copied from the RRset. Sign returns true when the signing went OK,
|
||||
// otherwise false.
|
||||
// There is no check if RRSet is a proper (RFC 2181) RRSet.
|
||||
// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset
|
||||
// is used as the OrigTTL.
|
||||
func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
|
||||
// Sign signs an RRSet. The signature needs to be filled in with the values:
|
||||
// Inception, Expiration, KeyTag, SignerName and Algorithm. The rest is copied
|
||||
// from the RRset. Sign returns a non-nill error when the signing went OK.
|
||||
// There is no check if RRSet is a proper (RFC 2181) RRSet. If OrigTTL is non
|
||||
// zero, it is used as-is, otherwise the TTL of the RRset is used as the
|
||||
// OrigTTL.
|
||||
func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
||||
if k == nil {
|
||||
return ErrPrivKey
|
||||
}
|
||||
|
|
@ -258,39 +300,66 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
|
|||
}
|
||||
signdata = append(signdata, wire...)
|
||||
|
||||
var h hash.Hash
|
||||
switch rr.Algorithm {
|
||||
case DSA, DSANSEC3SHA1:
|
||||
// TODO: this seems bugged, will panic
|
||||
case RSASHA1, RSASHA1NSEC3SHA1:
|
||||
h = sha1.New()
|
||||
case RSASHA256, ECDSAP256SHA256:
|
||||
h = sha256.New()
|
||||
case ECDSAP384SHA384:
|
||||
h = sha512.New384()
|
||||
case RSASHA512:
|
||||
h = sha512.New()
|
||||
case RSAMD5:
|
||||
fallthrough // Deprecated in RFC 6725
|
||||
default:
|
||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||
if !ok {
|
||||
return ErrAlg
|
||||
}
|
||||
|
||||
_, err = h.Write(signdata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sighash := h.Sum(nil)
|
||||
h := hash.New()
|
||||
h.Write(signdata)
|
||||
|
||||
signature, err := k.Sign(sighash, rr.Algorithm)
|
||||
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rr.Signature = toBase64(signature)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
|
||||
signature, err := k.Sign(rand.Reader, hashed, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch alg {
|
||||
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
|
||||
return signature, nil
|
||||
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
ecdsaSignature := &struct {
|
||||
R, S *big.Int
|
||||
}{}
|
||||
if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var intlen int
|
||||
switch alg {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
}
|
||||
|
||||
signature := intToBytes(ecdsaSignature.R, intlen)
|
||||
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
|
||||
return signature, nil
|
||||
|
||||
// There is no defined interface for what a DSA backed crypto.Signer returns
|
||||
case DSA, DSANSEC3SHA1:
|
||||
// t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
|
||||
// signature := []byte{byte(t)}
|
||||
// signature = append(signature, intToBytes(r1, 20)...)
|
||||
// signature = append(signature, intToBytes(s1, 20)...)
|
||||
// rr.Signature = signature
|
||||
}
|
||||
|
||||
return nil, ErrAlg
|
||||
}
|
||||
|
||||
// Verify validates an RRSet with the signature and key. This is only the
|
||||
// cryptographic test, the signature validity period must be checked separately.
|
||||
// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
|
||||
|
|
@ -351,8 +420,13 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||
|
||||
sigbuf := rr.sigBuf() // Get the binary signature data
|
||||
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
||||
// TODO(mg)
|
||||
// remove the domain name and assume its our
|
||||
// TODO(miek)
|
||||
// remove the domain name and assume its ours?
|
||||
}
|
||||
|
||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||
if !ok {
|
||||
return ErrAlg
|
||||
}
|
||||
|
||||
switch rr.Algorithm {
|
||||
|
|
@ -362,52 +436,31 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||
if pubkey == nil {
|
||||
return ErrKey
|
||||
}
|
||||
// Setup the hash as defined for this alg.
|
||||
var h hash.Hash
|
||||
var ch crypto.Hash
|
||||
switch rr.Algorithm {
|
||||
case RSAMD5:
|
||||
h = md5.New()
|
||||
ch = crypto.MD5
|
||||
case RSASHA1, RSASHA1NSEC3SHA1:
|
||||
h = sha1.New()
|
||||
ch = crypto.SHA1
|
||||
case RSASHA256:
|
||||
h = sha256.New()
|
||||
ch = crypto.SHA256
|
||||
case RSASHA512:
|
||||
h = sha512.New()
|
||||
ch = crypto.SHA512
|
||||
}
|
||||
io.WriteString(h, string(signeddata))
|
||||
sighash := h.Sum(nil)
|
||||
return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
|
||||
|
||||
h := hash.New()
|
||||
h.Write(signeddata)
|
||||
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
|
||||
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
pubkey := k.publicKeyECDSA()
|
||||
if pubkey == nil {
|
||||
return ErrKey
|
||||
}
|
||||
var h hash.Hash
|
||||
switch rr.Algorithm {
|
||||
case ECDSAP256SHA256:
|
||||
h = sha256.New()
|
||||
case ECDSAP384SHA384:
|
||||
h = sha512.New384()
|
||||
}
|
||||
io.WriteString(h, string(signeddata))
|
||||
sighash := h.Sum(nil)
|
||||
|
||||
// Split sigbuf into the r and s coordinates
|
||||
r := big.NewInt(0)
|
||||
r.SetBytes(sigbuf[:len(sigbuf)/2])
|
||||
s := big.NewInt(0)
|
||||
s.SetBytes(sigbuf[len(sigbuf)/2:])
|
||||
if ecdsa.Verify(pubkey, sighash, r, s) {
|
||||
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
|
||||
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
|
||||
|
||||
h := hash.New()
|
||||
h.Write(signeddata)
|
||||
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
||||
return nil
|
||||
}
|
||||
return ErrSig
|
||||
|
||||
default:
|
||||
return ErrAlg
|
||||
}
|
||||
// Unknown alg
|
||||
return ErrAlg
|
||||
}
|
||||
|
||||
// ValidityPeriod uses RFC1982 serial arithmetic to calculate
|
||||
|
|
@ -555,6 +608,12 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
|||
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
|
||||
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
|
||||
// SRV, DNAME, A6
|
||||
//
|
||||
// RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
|
||||
// Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
|
||||
// that needs conversion to lowercase, and twice at that. Since HINFO
|
||||
// records contain no domain names, they are not subject to case
|
||||
// conversion.
|
||||
switch x := r1.(type) {
|
||||
case *NS:
|
||||
x.Ns = strings.ToLower(x.Ns)
|
||||
|
|
@ -603,36 +662,3 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
|||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Map for algorithm names.
|
||||
var AlgorithmToString = map[uint8]string{
|
||||
RSAMD5: "RSAMD5",
|
||||
DH: "DH",
|
||||
DSA: "DSA",
|
||||
RSASHA1: "RSASHA1",
|
||||
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
|
||||
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
|
||||
RSASHA256: "RSASHA256",
|
||||
RSASHA512: "RSASHA512",
|
||||
ECCGOST: "ECC-GOST",
|
||||
ECDSAP256SHA256: "ECDSAP256SHA256",
|
||||
ECDSAP384SHA384: "ECDSAP384SHA384",
|
||||
INDIRECT: "INDIRECT",
|
||||
PRIVATEDNS: "PRIVATEDNS",
|
||||
PRIVATEOID: "PRIVATEOID",
|
||||
}
|
||||
|
||||
// Map of algorithm strings.
|
||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||
|
||||
// Map for hash names.
|
||||
var HashToString = map[uint8]string{
|
||||
SHA1: "SHA1",
|
||||
SHA256: "SHA256",
|
||||
GOST94: "GOST94",
|
||||
SHA384: "SHA384",
|
||||
SHA512: "SHA512",
|
||||
}
|
||||
|
||||
// Map of hash strings.
|
||||
var StringToHash = reverseInt8(HashToString)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
// what kind of DNSKEY will be generated.
|
||||
// The ECDSA algorithms imply a fixed keysize, in that case
|
||||
// bits should be set to the size of the algorithm.
|
||||
func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
|
||||
func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
|
||||
switch k.Algorithm {
|
||||
case DSA, DSANSEC3SHA1:
|
||||
if bits != 1024 {
|
||||
|
|
@ -52,14 +53,14 @@ func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
|
|||
return nil, err
|
||||
}
|
||||
k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
|
||||
return (*DSAPrivateKey)(priv), nil
|
||||
return priv, nil
|
||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
|
||||
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
|
||||
return (*RSAPrivateKey)(priv), nil
|
||||
return priv, nil
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
var c elliptic.Curve
|
||||
switch k.Algorithm {
|
||||
|
|
@ -73,7 +74,7 @@ func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
|
|||
return nil, err
|
||||
}
|
||||
k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
|
||||
return (*ECDSAPrivateKey)(priv), nil
|
||||
return priv, nil
|
||||
default:
|
||||
return nil, ErrAlg
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
|
|
@ -12,7 +13,7 @@ import (
|
|||
|
||||
// NewPrivateKey returns a PrivateKey by parsing the string s.
|
||||
// s should be in the same form of the BIND private key files.
|
||||
func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
|
||||
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
|
||||
if s[len(s)-1] != '\n' { // We need a closing newline
|
||||
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
|
||||
}
|
||||
|
|
@ -23,7 +24,7 @@ func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
|
|||
// only used in error reporting.
|
||||
// The public key must be known, because some cryptographic algorithms embed
|
||||
// the public inside the privatekey.
|
||||
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
|
||||
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
|
||||
m, e := parseKey(q, file)
|
||||
if m == nil {
|
||||
return nil, e
|
||||
|
|
@ -50,7 +51,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
|
|||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return (*DSAPrivateKey)(priv), e
|
||||
return priv, e
|
||||
case RSAMD5:
|
||||
fallthrough
|
||||
case RSASHA1:
|
||||
|
|
@ -69,7 +70,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
|
|||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return (*RSAPrivateKey)(priv), e
|
||||
return priv, e
|
||||
case ECCGOST:
|
||||
return nil, ErrPrivKey
|
||||
case ECDSAP256SHA256:
|
||||
|
|
@ -84,7 +85,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
|
|||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return (*ECDSAPrivateKey)(priv), e
|
||||
return priv, e
|
||||
default:
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
|
@ -12,133 +11,75 @@ import (
|
|||
|
||||
const format = "Private-key-format: v1.3\n"
|
||||
|
||||
// PrivateKey ... TODO(miek)
|
||||
type PrivateKey interface {
|
||||
Sign([]byte, uint8) ([]byte, error)
|
||||
String(uint8) string
|
||||
}
|
||||
|
||||
// PrivateKeyString converts a PrivateKey to a string. This string has the same
|
||||
// format as the private-key-file of BIND9 (Private-key-format: v1.3).
|
||||
// It needs some info from the key (the algorithm), so its a method of the
|
||||
// DNSKEY and calls PrivateKey.String(alg).
|
||||
func (r *DNSKEY) PrivateKeyString(p PrivateKey) string {
|
||||
return p.String(r.Algorithm)
|
||||
}
|
||||
// It needs some info from the key (the algorithm), so its a method of the DNSKEY
|
||||
// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey
|
||||
func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
|
||||
algorithm := strconv.Itoa(int(r.Algorithm))
|
||||
algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
|
||||
|
||||
type RSAPrivateKey rsa.PrivateKey
|
||||
switch p := p.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
modulus := toBase64(p.PublicKey.N.Bytes())
|
||||
e := big.NewInt(int64(p.PublicKey.E))
|
||||
publicExponent := toBase64(e.Bytes())
|
||||
privateExponent := toBase64(p.D.Bytes())
|
||||
prime1 := toBase64(p.Primes[0].Bytes())
|
||||
prime2 := toBase64(p.Primes[1].Bytes())
|
||||
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
|
||||
// and from: http://code.google.com/p/go/issues/detail?id=987
|
||||
one := big.NewInt(1)
|
||||
p1 := big.NewInt(0).Sub(p.Primes[0], one)
|
||||
q1 := big.NewInt(0).Sub(p.Primes[1], one)
|
||||
exp1 := big.NewInt(0).Mod(p.D, p1)
|
||||
exp2 := big.NewInt(0).Mod(p.D, q1)
|
||||
coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
|
||||
|
||||
exponent1 := toBase64(exp1.Bytes())
|
||||
exponent2 := toBase64(exp2.Bytes())
|
||||
coefficient := toBase64(coeff.Bytes())
|
||||
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"Modulus: " + modulus + "\n" +
|
||||
"PublicExponent: " + publicExponent + "\n" +
|
||||
"PrivateExponent: " + privateExponent + "\n" +
|
||||
"Prime1: " + prime1 + "\n" +
|
||||
"Prime2: " + prime2 + "\n" +
|
||||
"Exponent1: " + exponent1 + "\n" +
|
||||
"Exponent2: " + exponent2 + "\n" +
|
||||
"Coefficient: " + coefficient + "\n"
|
||||
|
||||
case *ecdsa.PrivateKey:
|
||||
var intlen int
|
||||
switch r.Algorithm {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
}
|
||||
private := toBase64(intToBytes(p.D, intlen))
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"PrivateKey: " + private + "\n"
|
||||
|
||||
case *dsa.PrivateKey:
|
||||
T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
|
||||
prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
|
||||
subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
|
||||
base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
|
||||
priv := toBase64(intToBytes(p.X, 20))
|
||||
pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"Prime(p): " + prime + "\n" +
|
||||
"Subprime(q): " + subprime + "\n" +
|
||||
"Base(g): " + base + "\n" +
|
||||
"Private_value(x): " + priv + "\n" +
|
||||
"Public_value(y): " + pub + "\n"
|
||||
|
||||
func (p *RSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
|
||||
var hash crypto.Hash
|
||||
switch alg {
|
||||
case RSASHA1, RSASHA1NSEC3SHA1:
|
||||
hash = crypto.SHA1
|
||||
case RSASHA256:
|
||||
hash = crypto.SHA256
|
||||
case RSASHA512:
|
||||
hash = crypto.SHA512
|
||||
default:
|
||||
return nil, ErrAlg
|
||||
return ""
|
||||
}
|
||||
return rsa.SignPKCS1v15(nil, (*rsa.PrivateKey)(p), hash, hashed)
|
||||
}
|
||||
|
||||
func (p *RSAPrivateKey) String(alg uint8) string {
|
||||
algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
|
||||
modulus := toBase64(p.PublicKey.N.Bytes())
|
||||
e := big.NewInt(int64(p.PublicKey.E))
|
||||
publicExponent := toBase64(e.Bytes())
|
||||
privateExponent := toBase64(p.D.Bytes())
|
||||
prime1 := toBase64(p.Primes[0].Bytes())
|
||||
prime2 := toBase64(p.Primes[1].Bytes())
|
||||
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
|
||||
// and from: http://code.google.com/p/go/issues/detail?id=987
|
||||
one := big.NewInt(1)
|
||||
p1 := big.NewInt(0).Sub(p.Primes[0], one)
|
||||
q1 := big.NewInt(0).Sub(p.Primes[1], one)
|
||||
exp1 := big.NewInt(0).Mod(p.D, p1)
|
||||
exp2 := big.NewInt(0).Mod(p.D, q1)
|
||||
coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
|
||||
|
||||
exponent1 := toBase64(exp1.Bytes())
|
||||
exponent2 := toBase64(exp2.Bytes())
|
||||
coefficient := toBase64(coeff.Bytes())
|
||||
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"Modulus: " + modulus + "\n" +
|
||||
"PublicExponent: " + publicExponent + "\n" +
|
||||
"PrivateExponent: " + privateExponent + "\n" +
|
||||
"Prime1: " + prime1 + "\n" +
|
||||
"Prime2: " + prime2 + "\n" +
|
||||
"Exponent1: " + exponent1 + "\n" +
|
||||
"Exponent2: " + exponent2 + "\n" +
|
||||
"Coefficient: " + coefficient + "\n"
|
||||
}
|
||||
|
||||
type ECDSAPrivateKey ecdsa.PrivateKey
|
||||
|
||||
func (p *ECDSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
|
||||
var intlen int
|
||||
switch alg {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
default:
|
||||
return nil, ErrAlg
|
||||
}
|
||||
r1, s1, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(p), hashed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature := intToBytes(r1, intlen)
|
||||
signature = append(signature, intToBytes(s1, intlen)...)
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
func (p *ECDSAPrivateKey) String(alg uint8) string {
|
||||
algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
|
||||
var intlen int
|
||||
switch alg {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
}
|
||||
private := toBase64(intToBytes(p.D, intlen))
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"PrivateKey: " + private + "\n"
|
||||
}
|
||||
|
||||
type DSAPrivateKey dsa.PrivateKey
|
||||
|
||||
func (p *DSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
|
||||
r1, s1, err := dsa.Sign(rand.Reader, (*dsa.PrivateKey)(p), hashed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
|
||||
signature := []byte{byte(t)}
|
||||
signature = append(signature, intToBytes(r1, 20)...)
|
||||
signature = append(signature, intToBytes(s1, 20)...)
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
func (p *DSAPrivateKey) String(alg uint8) string {
|
||||
algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
|
||||
T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
|
||||
prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
|
||||
subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
|
||||
base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
|
||||
priv := toBase64(intToBytes(p.X, 20))
|
||||
pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"Prime(p): " + prime + "\n" +
|
||||
"Subprime(q): " + subprime + "\n" +
|
||||
"Base(g): " + base + "\n" +
|
||||
"Private_value(x): " + priv + "\n" +
|
||||
"Public_value(y): " + pub + "\n"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,719 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getKey() *DNSKEY {
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
return key
|
||||
}
|
||||
|
||||
func getSoa() *SOA {
|
||||
soa := new(SOA)
|
||||
soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
||||
soa.Ns = "open.nlnetlabs.nl."
|
||||
soa.Mbox = "miekg.atoom.net."
|
||||
soa.Serial = 1293945905
|
||||
soa.Refresh = 14400
|
||||
soa.Retry = 3600
|
||||
soa.Expire = 604800
|
||||
soa.Minttl = 86400
|
||||
return soa
|
||||
}
|
||||
|
||||
func TestGenerateEC(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = ECDSAP256SHA256
|
||||
privkey, _ := key.Generate(256)
|
||||
t.Log(key.String())
|
||||
t.Log(key.PrivateKeyString(privkey))
|
||||
}
|
||||
|
||||
func TestGenerateDSA(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = DSA
|
||||
privkey, _ := key.Generate(1024)
|
||||
t.Log(key.String())
|
||||
t.Log(key.PrivateKeyString(privkey))
|
||||
}
|
||||
|
||||
func TestGenerateRSA(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
privkey, _ := key.Generate(1024)
|
||||
t.Log(key.String())
|
||||
t.Log(key.PrivateKeyString(privkey))
|
||||
}
|
||||
|
||||
func TestSecure(t *testing.T) {
|
||||
soa := getSoa()
|
||||
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.TypeCovered = TypeSOA
|
||||
sig.Algorithm = RSASHA256
|
||||
sig.Labels = 2
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.OrigTtl = 14400
|
||||
sig.KeyTag = 12051
|
||||
sig.SignerName = "miek.nl."
|
||||
sig.Signature = "oMCbslaAVIp/8kVtLSms3tDABpcPRUgHLrOR48OOplkYo+8TeEGWwkSwaz/MRo2fB4FxW0qj/hTlIjUGuACSd+b1wKdH5GvzRJc2pFmxtCbm55ygAh4EUL0F6U5cKtGJGSXxxg6UFCQ0doJCmiGFa78LolaUOXImJrk6AFrGa0M="
|
||||
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
|
||||
// It should validate. Period is checked separately, so this will keep on working
|
||||
if sig.Verify(key, []RR{soa}) != nil {
|
||||
t.Error("failure to validate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignature(t *testing.T) {
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr.Name = "miek.nl."
|
||||
sig.Hdr.Class = ClassINET
|
||||
sig.Hdr.Ttl = 3600
|
||||
sig.TypeCovered = TypeDNSKEY
|
||||
sig.Algorithm = RSASHA1
|
||||
sig.Labels = 2
|
||||
sig.OrigTtl = 4000
|
||||
sig.Expiration = 1000 //Thu Jan 1 02:06:40 CET 1970
|
||||
sig.Inception = 800 //Thu Jan 1 01:13:20 CET 1970
|
||||
sig.KeyTag = 34641
|
||||
sig.SignerName = "miek.nl."
|
||||
sig.Signature = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
|
||||
|
||||
// Should not be valid
|
||||
if sig.ValidityPeriod(time.Now()) {
|
||||
t.Error("should not be valid")
|
||||
}
|
||||
|
||||
sig.Inception = 315565800 //Tue Jan 1 10:10:00 CET 1980
|
||||
sig.Expiration = 4102477800 //Fri Jan 1 10:10:00 CET 2100
|
||||
if !sig.ValidityPeriod(time.Now()) {
|
||||
t.Error("should be valid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
// The record we want to sign
|
||||
soa := new(SOA)
|
||||
soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
||||
soa.Ns = "open.nlnetlabs.nl."
|
||||
soa.Mbox = "miekg.atoom.net."
|
||||
soa.Serial = 1293945905
|
||||
soa.Refresh = 14400
|
||||
soa.Retry = 3600
|
||||
soa.Expire = 604800
|
||||
soa.Minttl = 86400
|
||||
|
||||
soa1 := new(SOA)
|
||||
soa1.Hdr = RR_Header{"*.miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
||||
soa1.Ns = "open.nlnetlabs.nl."
|
||||
soa1.Mbox = "miekg.atoom.net."
|
||||
soa1.Serial = 1293945905
|
||||
soa1.Refresh = 14400
|
||||
soa1.Retry = 3600
|
||||
soa1.Expire = 604800
|
||||
soa1.Minttl = 86400
|
||||
|
||||
srv := new(SRV)
|
||||
srv.Hdr = RR_Header{"srv.miek.nl.", TypeSRV, ClassINET, 14400, 0}
|
||||
srv.Port = 1000
|
||||
srv.Weight = 800
|
||||
srv.Target = "web1.miek.nl."
|
||||
|
||||
// With this key
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
privkey, _ := key.Generate(512)
|
||||
|
||||
// Fill in the values of the Sig, before signing
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.TypeCovered = soa.Hdr.Rrtype
|
||||
sig.Labels = uint8(CountLabel(soa.Hdr.Name)) // works for all 3
|
||||
sig.OrigTtl = soa.Hdr.Ttl
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.KeyTag = key.KeyTag() // Get the keyfrom the Key
|
||||
sig.SignerName = key.Hdr.Name
|
||||
sig.Algorithm = RSASHA256
|
||||
|
||||
for _, r := range []RR{soa, soa1, srv} {
|
||||
if sig.Sign(privkey, []RR{r}) != nil {
|
||||
t.Error("failure to sign the record")
|
||||
continue
|
||||
}
|
||||
if sig.Verify(key, []RR{r}) != nil {
|
||||
t.Error("failure to validate")
|
||||
continue
|
||||
}
|
||||
t.Logf("validated: %s", r.Header().Name)
|
||||
}
|
||||
}
|
||||
|
||||
func Test65534(t *testing.T) {
|
||||
t6 := new(RFC3597)
|
||||
t6.Hdr = RR_Header{"miek.nl.", 65534, ClassINET, 14400, 0}
|
||||
t6.Rdata = "505D870001"
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
privkey, _ := key.Generate(1024)
|
||||
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.TypeCovered = t6.Hdr.Rrtype
|
||||
sig.Labels = uint8(CountLabel(t6.Hdr.Name))
|
||||
sig.OrigTtl = t6.Hdr.Ttl
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.KeyTag = key.KeyTag()
|
||||
sig.SignerName = key.Hdr.Name
|
||||
sig.Algorithm = RSASHA256
|
||||
if err := sig.Sign(privkey, []RR{t6}); err != nil {
|
||||
t.Error(err)
|
||||
t.Error("failure to sign the TYPE65534 record")
|
||||
}
|
||||
if err := sig.Verify(key, []RR{t6}); err != nil {
|
||||
t.Error(err)
|
||||
t.Error("failure to validate")
|
||||
} else {
|
||||
t.Logf("validated: %s", t6.Header().Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDnskey(t *testing.T) {
|
||||
pubkey, err := ReadRR(strings.NewReader(`
|
||||
miek.nl. IN DNSKEY 256 3 10 AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL ;{id = 5240 (zsk), size = 1024b}
|
||||
`), "Kmiek.nl.+010+05240.key")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
privStr := `Private-key-format: v1.3
|
||||
Algorithm: 10 (RSASHA512)
|
||||
Modulus: m4wK7YV26AeROtdiCXmqLG9wPDVoMOW8vjr/EkpscEAdjXp81RvZvrlzCSjYmz9onFRgltmTl3AINnFh+t9tlW0M9C5zejxBoKFXELv8ljPYAdz2oe+pDWPhWsfvVFYg2VCjpViPM38EakyE5mhk4TDOnUd+w4TeU1hyhZTWyYs=
|
||||
PublicExponent: AQAB
|
||||
PrivateExponent: UfCoIQ/Z38l8vB6SSqOI/feGjHEl/fxIPX4euKf0D/32k30fHbSaNFrFOuIFmWMB3LimWVEs6u3dpbB9CQeCVg7hwU5puG7OtuiZJgDAhNeOnxvo5btp4XzPZrJSxR4WNQnwIiYWbl0aFlL1VGgHC/3By89ENZyWaZcMLW4KGWE=
|
||||
Prime1: yxwC6ogAu8aVcDx2wg1V0b5M5P6jP8qkRFVMxWNTw60Vkn+ECvw6YAZZBHZPaMyRYZLzPgUlyYRd0cjupy4+fQ==
|
||||
Prime2: xA1bF8M0RTIQ6+A11AoVG6GIR/aPGg5sogRkIZ7ID/sF6g9HMVU/CM2TqVEBJLRPp73cv6ZeC3bcqOCqZhz+pw==
|
||||
Exponent1: xzkblyZ96bGYxTVZm2/vHMOXswod4KWIyMoOepK6B/ZPcZoIT6omLCgtypWtwHLfqyCz3MK51Nc0G2EGzg8rFQ==
|
||||
Exponent2: Pu5+mCEb7T5F+kFNZhQadHUklt0JUHbi3hsEvVoHpEGSw3BGDQrtIflDde0/rbWHgDPM4WQY+hscd8UuTXrvLw==
|
||||
Coefficient: UuRoNqe7YHnKmQzE6iDWKTMIWTuoqqrFAmXPmKQnC+Y+BQzOVEHUo9bXdDnoI9hzXP1gf8zENMYwYLeWpuYlFQ==
|
||||
`
|
||||
privkey, err := pubkey.(*DNSKEY).ReadPrivateKey(strings.NewReader(privStr),
|
||||
"Kmiek.nl.+010+05240.private")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pubkey.(*DNSKEY).PublicKey != "AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL" {
|
||||
t.Error("pubkey is not what we've read")
|
||||
}
|
||||
if pubkey.(*DNSKEY).PrivateKeyString(privkey) != privStr {
|
||||
t.Error("privkey is not what we've read")
|
||||
t.Errorf("%v", pubkey.(*DNSKEY).PrivateKeyString(privkey))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTag(t *testing.T) {
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 3600
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
|
||||
tag := key.KeyTag()
|
||||
if tag != 12051 {
|
||||
t.Errorf("wrong key tag: %d for key %v", tag, key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyRSA(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 3600
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
priv, _ := key.Generate(2048)
|
||||
|
||||
soa := new(SOA)
|
||||
soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
||||
soa.Ns = "open.nlnetlabs.nl."
|
||||
soa.Mbox = "miekg.atoom.net."
|
||||
soa.Serial = 1293945905
|
||||
soa.Refresh = 14400
|
||||
soa.Retry = 3600
|
||||
soa.Expire = 604800
|
||||
soa.Minttl = 86400
|
||||
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.TypeCovered = TypeSOA
|
||||
sig.Algorithm = RSASHA256
|
||||
sig.Labels = 2
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.OrigTtl = soa.Hdr.Ttl
|
||||
sig.KeyTag = key.KeyTag()
|
||||
sig.SignerName = key.Hdr.Name
|
||||
|
||||
if err := sig.Sign(priv, []RR{soa}); err != nil {
|
||||
t.Error("failed to sign")
|
||||
return
|
||||
}
|
||||
if err := sig.Verify(key, []RR{soa}); err != nil {
|
||||
t.Error("failed to verify")
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyToDS(t *testing.T) {
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 3600
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
|
||||
ds := key.ToDS(SHA1)
|
||||
if strings.ToUpper(ds.Digest) != "B5121BDB5B8D86D0CC5FFAFBAAABE26C3E20BAC1" {
|
||||
t.Errorf("wrong DS digest for SHA1\n%v", ds)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignRSA(t *testing.T) {
|
||||
pub := "miek.nl. IN DNSKEY 256 3 5 AwEAAb+8lGNCxJgLS8rYVer6EnHVuIkQDghdjdtewDzU3G5R7PbMbKVRvH2Ma7pQyYceoaqWZQirSj72euPWfPxQnMy9ucCylA+FuH9cSjIcPf4PqJfdupHk9X6EBYjxrCLY4p1/yBwgyBIRJtZtAqM3ceAH2WovEJD6rTtOuHo5AluJ"
|
||||
|
||||
priv := `Private-key-format: v1.3
|
||||
Algorithm: 5 (RSASHA1)
|
||||
Modulus: v7yUY0LEmAtLythV6voScdW4iRAOCF2N217APNTcblHs9sxspVG8fYxrulDJhx6hqpZlCKtKPvZ649Z8/FCczL25wLKUD4W4f1xKMhw9/g+ol926keT1foQFiPGsItjinX/IHCDIEhEm1m0Cozdx4AfZai8QkPqtO064ejkCW4k=
|
||||
PublicExponent: AQAB
|
||||
PrivateExponent: YPwEmwjk5HuiROKU4xzHQ6l1hG8Iiha4cKRG3P5W2b66/EN/GUh07ZSf0UiYB67o257jUDVEgwCuPJz776zfApcCB4oGV+YDyEu7Hp/rL8KcSN0la0k2r9scKwxTp4BTJT23zyBFXsV/1wRDK1A5NxsHPDMYi2SoK63Enm/1ptk=
|
||||
Prime1: /wjOG+fD0ybNoSRn7nQ79udGeR1b0YhUA5mNjDx/x2fxtIXzygYk0Rhx9QFfDy6LOBvz92gbNQlzCLz3DJt5hw==
|
||||
Prime2: wHZsJ8OGhkp5p3mrJFZXMDc2mbYusDVTA+t+iRPdS797Tj0pjvU2HN4vTnTj8KBQp6hmnY7dLp9Y1qserySGbw==
|
||||
Exponent1: N0A7FsSRIg+IAN8YPQqlawoTtG1t1OkJ+nWrurPootScApX6iMvn8fyvw3p2k51rv84efnzpWAYiC8SUaQDNxQ==
|
||||
Exponent2: SvuYRaGyvo0zemE3oS+WRm2scxR8eiA8WJGeOc+obwOKCcBgeZblXzfdHGcEC1KaOcetOwNW/vwMA46lpLzJNw==
|
||||
Coefficient: 8+7ZN/JgByqv0NfULiFKTjtyegUcijRuyij7yNxYbCBneDvZGxJwKNi4YYXWx743pcAj4Oi4Oh86gcmxLs+hGw==
|
||||
Created: 20110302104537
|
||||
Publish: 20110302104537
|
||||
Activate: 20110302104537`
|
||||
|
||||
xk, _ := NewRR(pub)
|
||||
k := xk.(*DNSKEY)
|
||||
p, err := k.NewPrivateKey(priv)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
switch priv := p.(type) {
|
||||
case *RSAPrivateKey:
|
||||
if 65537 != priv.PublicKey.E {
|
||||
t.Error("exponenent should be 65537")
|
||||
}
|
||||
default:
|
||||
t.Errorf("we should have read an RSA key: %v", priv)
|
||||
}
|
||||
if k.KeyTag() != 37350 {
|
||||
t.Errorf("keytag should be 37350, got %d %v", k.KeyTag(), k)
|
||||
}
|
||||
|
||||
soa := new(SOA)
|
||||
soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
||||
soa.Ns = "open.nlnetlabs.nl."
|
||||
soa.Mbox = "miekg.atoom.net."
|
||||
soa.Serial = 1293945905
|
||||
soa.Refresh = 14400
|
||||
soa.Retry = 3600
|
||||
soa.Expire = 604800
|
||||
soa.Minttl = 86400
|
||||
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.KeyTag = k.KeyTag()
|
||||
sig.SignerName = k.Hdr.Name
|
||||
sig.Algorithm = k.Algorithm
|
||||
|
||||
sig.Sign(p, []RR{soa})
|
||||
if sig.Signature != "D5zsobpQcmMmYsUMLxCVEtgAdCvTu8V/IEeP4EyLBjqPJmjt96bwM9kqihsccofA5LIJ7DN91qkCORjWSTwNhzCv7bMyr2o5vBZElrlpnRzlvsFIoAZCD9xg6ZY7ZyzUJmU6IcTwG4v3xEYajcpbJJiyaw/RqR90MuRdKPiBzSo=" {
|
||||
t.Errorf("signature is not correct: %v", sig)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerifyECDSA(t *testing.T) {
|
||||
pub := `example.net. 3600 IN DNSKEY 257 3 14 (
|
||||
xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1
|
||||
w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8
|
||||
/uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )`
|
||||
priv := `Private-key-format: v1.2
|
||||
Algorithm: 14 (ECDSAP384SHA384)
|
||||
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
|
||||
eckey, err := NewRR(pub)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
privkey, err := eckey.(*DNSKEY).NewPrivateKey(priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// TODO: Create separate test for this
|
||||
ds := eckey.(*DNSKEY).ToDS(SHA384)
|
||||
if ds.KeyTag != 10771 {
|
||||
t.Fatal("wrong keytag on DS")
|
||||
}
|
||||
if ds.Digest != "72d7b62976ce06438e9c0bf319013cf801f09ecc84b8d7e9495f27e305c6a9b0563a9b5f4d288405c3008a946df983d6" {
|
||||
t.Fatal("wrong DS Digest")
|
||||
}
|
||||
a, _ := NewRR("www.example.net. 3600 IN A 192.0.2.1")
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"example.net.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.Expiration, _ = StringToTime("20100909102025")
|
||||
sig.Inception, _ = StringToTime("20100812102025")
|
||||
sig.KeyTag = eckey.(*DNSKEY).KeyTag()
|
||||
sig.SignerName = eckey.(*DNSKEY).Hdr.Name
|
||||
sig.Algorithm = eckey.(*DNSKEY).Algorithm
|
||||
|
||||
if sig.Sign(privkey, []RR{a}) != nil {
|
||||
t.Fatal("failure to sign the record")
|
||||
}
|
||||
|
||||
if err := sig.Verify(eckey.(*DNSKEY), []RR{a}); err != nil {
|
||||
t.Fatalf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
|
||||
eckey.(*DNSKEY).String(),
|
||||
a.String(),
|
||||
sig.String(),
|
||||
eckey.(*DNSKEY).PrivateKeyString(privkey),
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerifyECDSA2(t *testing.T) {
|
||||
srv1, err := NewRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srv := srv1.(*SRV)
|
||||
|
||||
// With this key
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = ECDSAP256SHA256
|
||||
privkey, err := key.Generate(256)
|
||||
if err != nil {
|
||||
t.Fatal("failure to generate key")
|
||||
}
|
||||
|
||||
// Fill in the values of the Sig, before signing
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.TypeCovered = srv.Hdr.Rrtype
|
||||
sig.Labels = uint8(CountLabel(srv.Hdr.Name)) // works for all 3
|
||||
sig.OrigTtl = srv.Hdr.Ttl
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.KeyTag = key.KeyTag() // Get the keyfrom the Key
|
||||
sig.SignerName = key.Hdr.Name
|
||||
sig.Algorithm = ECDSAP256SHA256
|
||||
|
||||
if sig.Sign(privkey, []RR{srv}) != nil {
|
||||
t.Fatal("failure to sign the record")
|
||||
}
|
||||
|
||||
err = sig.Verify(key, []RR{srv})
|
||||
if err != nil {
|
||||
t.Logf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
|
||||
key.String(),
|
||||
srv.String(),
|
||||
sig.String(),
|
||||
key.PrivateKeyString(privkey),
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Here the test vectors from the relevant RFCs are checked.
|
||||
// rfc6605 6.1
|
||||
func TestRFC6605P256(t *testing.T) {
|
||||
exDNSKEY := `example.net. 3600 IN DNSKEY 257 3 13 (
|
||||
GojIhhXUN/u4v54ZQqGSnyhWJwaubCvTmeexv7bR6edb
|
||||
krSqQpF64cYbcB7wNcP+e+MAnLr+Wi9xMWyQLc8NAA== )`
|
||||
exPriv := `Private-key-format: v1.2
|
||||
Algorithm: 13 (ECDSAP256SHA256)
|
||||
PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
|
||||
rrDNSKEY, err := NewRR(exDNSKEY)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exDS := `example.net. 3600 IN DS 55648 13 2 (
|
||||
b4c8c1fe2e7477127b27115656ad6256f424625bf5c1
|
||||
e2770ce6d6e37df61d17 )`
|
||||
rrDS, err := NewRR(exDS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA256)
|
||||
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
|
||||
t.Errorf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
|
||||
}
|
||||
|
||||
exA := `www.example.net. 3600 IN A 192.0.2.1`
|
||||
exRRSIG := `www.example.net. 3600 IN RRSIG A 13 3 3600 (
|
||||
20100909100439 20100812100439 55648 example.net.
|
||||
qx6wLYqmh+l9oCKTN6qIc+bw6ya+KJ8oMz0YP107epXA
|
||||
yGmt+3SNruPFKG7tZoLBLlUzGGus7ZwmwWep666VCw== )`
|
||||
rrA, err := NewRR(exA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrRRSIG, err := NewRR(exRRSIG)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
|
||||
t.Errorf("Failure to validate the spec RRSIG: %v", err)
|
||||
}
|
||||
|
||||
ourRRSIG := &RRSIG{
|
||||
Hdr: RR_Header{
|
||||
Ttl: rrA.Header().Ttl,
|
||||
},
|
||||
KeyTag: rrDNSKEY.(*DNSKEY).KeyTag(),
|
||||
SignerName: rrDNSKEY.(*DNSKEY).Hdr.Name,
|
||||
Algorithm: rrDNSKEY.(*DNSKEY).Algorithm,
|
||||
}
|
||||
ourRRSIG.Expiration, _ = StringToTime("20100909100439")
|
||||
ourRRSIG.Inception, _ = StringToTime("20100812100439")
|
||||
err = ourRRSIG.Sign(priv, []RR{rrA})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
|
||||
t.Errorf("Failure to validate our RRSIG: %v", err)
|
||||
}
|
||||
|
||||
// Signatures are randomized
|
||||
rrRRSIG.(*RRSIG).Signature = ""
|
||||
ourRRSIG.Signature = ""
|
||||
if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) {
|
||||
t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG))
|
||||
}
|
||||
}
|
||||
|
||||
// rfc6605 6.2
|
||||
func TestRFC6605P384(t *testing.T) {
|
||||
exDNSKEY := `example.net. 3600 IN DNSKEY 257 3 14 (
|
||||
xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1
|
||||
w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8
|
||||
/uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )`
|
||||
exPriv := `Private-key-format: v1.2
|
||||
Algorithm: 14 (ECDSAP384SHA384)
|
||||
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
rrDNSKEY, err := NewRR(exDNSKEY)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
exDS := `example.net. 3600 IN DS 10771 14 4 (
|
||||
72d7b62976ce06438e9c0bf319013cf801f09ecc84b8
|
||||
d7e9495f27e305c6a9b0563a9b5f4d288405c3008a94
|
||||
6df983d6 )`
|
||||
rrDS, err := NewRR(exDS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA384)
|
||||
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
|
||||
t.Fatalf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
|
||||
}
|
||||
|
||||
exA := `www.example.net. 3600 IN A 192.0.2.1`
|
||||
exRRSIG := `www.example.net. 3600 IN RRSIG A 14 3 3600 (
|
||||
20100909102025 20100812102025 10771 example.net.
|
||||
/L5hDKIvGDyI1fcARX3z65qrmPsVz73QD1Mr5CEqOiLP
|
||||
95hxQouuroGCeZOvzFaxsT8Glr74hbavRKayJNuydCuz
|
||||
WTSSPdz7wnqXL5bdcJzusdnI0RSMROxxwGipWcJm )`
|
||||
rrA, err := NewRR(exA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrRRSIG, err := NewRR(exRRSIG)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
|
||||
t.Errorf("Failure to validate the spec RRSIG: %v", err)
|
||||
}
|
||||
|
||||
ourRRSIG := &RRSIG{
|
||||
Hdr: RR_Header{
|
||||
Ttl: rrA.Header().Ttl,
|
||||
},
|
||||
KeyTag: rrDNSKEY.(*DNSKEY).KeyTag(),
|
||||
SignerName: rrDNSKEY.(*DNSKEY).Hdr.Name,
|
||||
Algorithm: rrDNSKEY.(*DNSKEY).Algorithm,
|
||||
}
|
||||
ourRRSIG.Expiration, _ = StringToTime("20100909102025")
|
||||
ourRRSIG.Inception, _ = StringToTime("20100812102025")
|
||||
err = ourRRSIG.Sign(priv, []RR{rrA})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
|
||||
t.Errorf("Failure to validate our RRSIG: %v", err)
|
||||
}
|
||||
|
||||
// Signatures are randomized
|
||||
rrRRSIG.(*RRSIG).Signature = ""
|
||||
ourRRSIG.Signature = ""
|
||||
if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) {
|
||||
t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidRRSet(t *testing.T) {
|
||||
goodRecords := make([]RR, 2)
|
||||
goodRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
goodRecords[1] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"_o/"}}
|
||||
|
||||
// Generate key
|
||||
keyname := "cloudflare.com."
|
||||
key := &DNSKEY{
|
||||
Hdr: RR_Header{Name: keyname, Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 0},
|
||||
Algorithm: ECDSAP256SHA256,
|
||||
Flags: ZONE,
|
||||
Protocol: 3,
|
||||
}
|
||||
privatekey, err := key.Generate(256)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// Need to fill in: Inception, Expiration, KeyTag, SignerName and Algorithm
|
||||
curTime := time.Now()
|
||||
signature := &RRSIG{
|
||||
Inception: uint32(curTime.Unix()),
|
||||
Expiration: uint32(curTime.Add(time.Hour).Unix()),
|
||||
KeyTag: key.KeyTag(),
|
||||
SignerName: keyname,
|
||||
Algorithm: ECDSAP256SHA256,
|
||||
}
|
||||
|
||||
// Inconsistent name between records
|
||||
badRecords := make([]RR, 2)
|
||||
badRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
badRecords[1] = &TXT{Hdr: RR_Header{Name: "nama.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"_o/"}}
|
||||
|
||||
if IsRRset(badRecords) {
|
||||
t.Fatal("Record set with inconsistent names considered valid")
|
||||
}
|
||||
|
||||
badRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
badRecords[1] = &A{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeA, Class: ClassINET, Ttl: 0}}
|
||||
|
||||
if IsRRset(badRecords) {
|
||||
t.Fatal("Record set with inconsistent record types considered valid")
|
||||
}
|
||||
|
||||
badRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
badRecords[1] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassCHAOS, Ttl: 0}, Txt: []string{"_o/"}}
|
||||
|
||||
if IsRRset(badRecords) {
|
||||
t.Fatal("Record set with inconsistent record class considered valid")
|
||||
}
|
||||
|
||||
// Sign the good record set and then make sure verification fails on the bad record set
|
||||
if err := signature.Sign(privatekey, goodRecords); err != nil {
|
||||
t.Fatal("Signing good records failed")
|
||||
}
|
||||
|
||||
if err := signature.Verify(key, badRecords); err != ErrRRset {
|
||||
t.Fatal("Verification did not return ErrRRset with inconsistent records")
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,8 @@ Resource records are native types. They are not stored in wire format.
|
|||
Basic usage pattern for creating a new resource record:
|
||||
|
||||
r := new(dns.MX)
|
||||
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
|
||||
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
|
||||
Class: dns.ClassINET, Ttl: 3600}
|
||||
r.Preference = 10
|
||||
r.Mx = "mx.miek.nl."
|
||||
|
||||
|
|
@ -57,8 +58,8 @@ server configured on 127.0.0.1 and port 53:
|
|||
c := new(dns.Client)
|
||||
in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
|
||||
|
||||
Suppressing
|
||||
multiple outstanding queries (with the same question, type and class) is as easy as setting:
|
||||
Suppressing multiple outstanding queries (with the same question, type and
|
||||
class) is as easy as setting:
|
||||
|
||||
c.SingleInflight = true
|
||||
|
||||
|
|
@ -118,7 +119,7 @@ certain resource records or names in a zone to specify if resource records
|
|||
should be added or removed. The table from RFC 2136 supplemented with the Go
|
||||
DNS function shows which functions exist to specify the prerequisites.
|
||||
|
||||
3.2.4 - Table Of Metavalues Used In Prerequisite Section
|
||||
3.2.4 - Table Of Metavalues Used In Prerequisite Section
|
||||
|
||||
CLASS TYPE RDATA Meaning Function
|
||||
--------------------------------------------------------------
|
||||
|
|
@ -133,7 +134,7 @@ If you have decided on the prerequisites you can tell what RRs should
|
|||
be added or deleted. The next table shows the options you have and
|
||||
what functions to call.
|
||||
|
||||
3.4.2.6 - Table Of Metavalues Used In Update Section
|
||||
3.4.2.6 - Table Of Metavalues Used In Update Section
|
||||
|
||||
CLASS TYPE RDATA Meaning Function
|
||||
---------------------------------------------------------------
|
||||
|
|
@ -183,7 +184,7 @@ Basic use pattern validating and replying to a message that has TSIG set.
|
|||
dns.HandleFunc(".", handleRequest)
|
||||
|
||||
func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
m := new(Msg)
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
if r.IsTsig() {
|
||||
if w.TsigStatus() == nil {
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
package dns
|
||||
|
||||
// Find better solution
|
||||
|
|
@ -30,10 +30,6 @@ type OPT struct {
|
|||
Option []EDNS0 `dns:"opt"`
|
||||
}
|
||||
|
||||
func (rr *OPT) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *OPT) String() string {
|
||||
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
|
||||
if rr.Do() {
|
||||
|
|
@ -87,10 +83,6 @@ func (rr *OPT) len() int {
|
|||
return l
|
||||
}
|
||||
|
||||
func (rr *OPT) copy() RR {
|
||||
return &OPT{*rr.Hdr.copyHeader(), rr.Option}
|
||||
}
|
||||
|
||||
// return the old value -> delete SetVersion?
|
||||
|
||||
// Version returns the EDNS version used. Only zero is defined.
|
||||
|
|
@ -176,7 +168,7 @@ func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
|
|||
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
|
||||
func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
||||
|
||||
// The subnet EDNS0 option is used to give the remote nameserver
|
||||
// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
|
||||
// an idea of where the client lives. It can then give back a different
|
||||
// answer depending on the location or network topology.
|
||||
// Basic use pattern for creating an subnet option:
|
||||
|
|
@ -291,7 +283,7 @@ func (e *EDNS0_SUBNET) String() (s string) {
|
|||
return
|
||||
}
|
||||
|
||||
// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set
|
||||
// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
|
||||
// an expiration on an update RR. This is helpful for clients that cannot clean
|
||||
// up after themselves. This is a draft RFC and more information can be found at
|
||||
// http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||
|
|
@ -329,7 +321,7 @@ func (e *EDNS0_UL) unpack(b []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||
// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||
// Implemented for completeness, as the EDNS0 type code is assigned.
|
||||
type EDNS0_LLQ struct {
|
||||
Code uint16 // Always EDNS0LLQ
|
||||
|
|
@ -471,7 +463,7 @@ func (e *EDNS0_EXPIRE) unpack(b []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// The local EDNS0 option is used for local/experimental purposes. The option
|
||||
// The EDNS0_LOCAL option is used for local/experimental purposes. The option
|
||||
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
|
||||
// (RFC6891), although any unassigned code can actually be used. The content of
|
||||
// the option is made available in Data, unaltered.
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
package dns
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestOPTTtl(t *testing.T) {
|
||||
e := &OPT{}
|
||||
e.Hdr.Name = "."
|
||||
e.Hdr.Rrtype = TypeOPT
|
||||
|
||||
if e.Do() {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
e.SetDo()
|
||||
if !e.Do() {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
oldTtl := e.Hdr.Ttl
|
||||
|
||||
if e.Version() != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
e.SetVersion(42)
|
||||
if e.Version() != 42 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
e.SetVersion(0)
|
||||
if e.Hdr.Ttl != oldTtl {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if e.ExtendedRcode() != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
e.SetExtendedRcode(42)
|
||||
if e.ExtendedRcode() != 42 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
e.SetExtendedRcode(0)
|
||||
if e.Hdr.Ttl != oldTtl {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
package dns_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Retrieve the MX records for miek.nl.
|
||||
func ExampleMX() {
|
||||
config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
c := new(dns.Client)
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("miek.nl.", dns.TypeMX)
|
||||
m.RecursionDesired = true
|
||||
r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if r.Rcode != dns.RcodeSuccess {
|
||||
return
|
||||
}
|
||||
for _, a := range r.Answer {
|
||||
if mx, ok := a.(*dns.MX); ok {
|
||||
fmt.Printf("%s\n", mx.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the DNSKEY records of a zone and convert them
|
||||
// to DS records for SHA1, SHA256 and SHA384.
|
||||
func ExampleDS(zone string) {
|
||||
config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
c := new(dns.Client)
|
||||
m := new(dns.Msg)
|
||||
if zone == "" {
|
||||
zone = "miek.nl"
|
||||
}
|
||||
m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY)
|
||||
m.SetEdns0(4096, true)
|
||||
r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if r.Rcode != dns.RcodeSuccess {
|
||||
return
|
||||
}
|
||||
for _, k := range r.Answer {
|
||||
if key, ok := k.(*dns.DNSKEY); ok {
|
||||
for _, alg := range []uint8{dns.SHA1, dns.SHA256, dns.SHA384} {
|
||||
fmt.Printf("%s; %d\n", key.ToDS(alg).String(), key.Flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TypeAPAIR = 0x0F99
|
||||
|
||||
type APAIR struct {
|
||||
addr [2]net.IP
|
||||
}
|
||||
|
||||
func NewAPAIR() dns.PrivateRdata { return new(APAIR) }
|
||||
|
||||
func (rd *APAIR) String() string { return rd.addr[0].String() + " " + rd.addr[1].String() }
|
||||
func (rd *APAIR) Parse(txt []string) error {
|
||||
if len(txt) != 2 {
|
||||
return errors.New("two addresses required for APAIR")
|
||||
}
|
||||
for i, s := range txt {
|
||||
ip := net.ParseIP(s)
|
||||
if ip == nil {
|
||||
return errors.New("invalid IP in APAIR text representation")
|
||||
}
|
||||
rd.addr[i] = ip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rd *APAIR) Pack(buf []byte) (int, error) {
|
||||
b := append([]byte(rd.addr[0]), []byte(rd.addr[1])...)
|
||||
n := copy(buf, b)
|
||||
if n != len(b) {
|
||||
return n, dns.ErrBuf
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (rd *APAIR) Unpack(buf []byte) (int, error) {
|
||||
ln := net.IPv4len * 2
|
||||
if len(buf) != ln {
|
||||
return 0, errors.New("invalid length of APAIR rdata")
|
||||
}
|
||||
cp := make([]byte, ln)
|
||||
copy(cp, buf) // clone bytes to use them in IPs
|
||||
|
||||
rd.addr[0] = net.IP(cp[:3])
|
||||
rd.addr[1] = net.IP(cp[4:])
|
||||
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func (rd *APAIR) Copy(dest dns.PrivateRdata) error {
|
||||
cp := make([]byte, rd.Len())
|
||||
_, err := rd.Pack(cp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d := dest.(*APAIR)
|
||||
d.addr[0] = net.IP(cp[:3])
|
||||
d.addr[1] = net.IP(cp[4:])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rd *APAIR) Len() int {
|
||||
return net.IPv4len * 2
|
||||
}
|
||||
|
||||
func ExamplePrivateHandle() {
|
||||
dns.PrivateHandle("APAIR", TypeAPAIR, NewAPAIR)
|
||||
defer dns.PrivateHandleRemove(TypeAPAIR)
|
||||
|
||||
rr, err := dns.NewRR("miek.nl. APAIR (1.2.3.4 1.2.3.5)")
|
||||
if err != nil {
|
||||
log.Fatal("could not parse APAIR record: ", err)
|
||||
}
|
||||
fmt.Println(rr)
|
||||
// Output: miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.Id = 12345
|
||||
m.SetQuestion("miek.nl.", TypeAPAIR)
|
||||
m.Answer = append(m.Answer, rr)
|
||||
|
||||
fmt.Println(m)
|
||||
// ;; opcode: QUERY, status: NOERROR, id: 12345
|
||||
// ;; flags: rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
|
||||
//
|
||||
// ;; QUESTION SECTION:
|
||||
// ;miek.nl. IN APAIR
|
||||
//
|
||||
// ;; ANSWER SECTION:
|
||||
// miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package dns
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFuzzString(t *testing.T) {
|
||||
testcases := []string{"", " MINFO ", " RP ", " NSEC 0 0", " \" NSEC 0 0\"", " \" MINFO \"",
|
||||
";a ", ";a<><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
|
||||
" NSAP O ", " NSAP N ",
|
||||
" TYPE4 TYPE6a789a3bc0045c8a5fb42c7d1bd998f5444 IN 9579b47d46817afbd17273e6",
|
||||
" TYPE45 3 3 4147994 TYPE\\(\\)\\)\\(\\)\\(\\(\\)\\(\\)\\)\\)\\(\\)\\(\\)\\(\\(\\R 948\"\")\\(\\)\\)\\)\\(\\ ",
|
||||
"$GENERATE 0-3 ${441189,5039418474430,o}",
|
||||
"$INCLUDE 00 TYPE00000000000n ",
|
||||
"$INCLUDE PE4 TYPE061463623/727071511 \\(\\)\\$GENERATE 6-462/0",
|
||||
}
|
||||
for i, tc := range testcases {
|
||||
rr, err := NewRR(tc)
|
||||
if err == nil {
|
||||
// rr can be nil because we can (for instance) just parse a comment
|
||||
if rr == nil {
|
||||
continue
|
||||
}
|
||||
t.Fatalf("parsed mailformed RR %d: %s", i, rr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package idn_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns/idn"
|
||||
)
|
||||
|
||||
func ExampleToPunycode() {
|
||||
name := "インターネット.テスト"
|
||||
fmt.Printf("%s -> %s", name, idn.ToPunycode(name))
|
||||
// Output: インターネット.テスト -> xn--eckucmux0ukc.xn--zckzah
|
||||
}
|
||||
|
||||
func ExampleFromPunycode() {
|
||||
name := "xn--mgbaja8a1hpac.xn--mgbachtv"
|
||||
fmt.Printf("%s -> %s", name, idn.FromPunycode(name))
|
||||
// Output: xn--mgbaja8a1hpac.xn--mgbachtv -> الانترنت.اختبار
|
||||
}
|
||||
|
|
@ -199,7 +199,6 @@ func needFromPunycode(s string) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// encode transforms Unicode input bytes (that represent DNS label) into
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
package idn
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testcases = [][2]string{
|
||||
{"", ""},
|
||||
{"a", "a"},
|
||||
{"a-b", "a-b"},
|
||||
{"a-b-c", "a-b-c"},
|
||||
{"abc", "abc"},
|
||||
{"я", "xn--41a"},
|
||||
{"zя", "xn--z-0ub"},
|
||||
{"яZ", "xn--z-zub"},
|
||||
{"а-я", "xn----7sb8g"},
|
||||
{"إختبار", "xn--kgbechtv"},
|
||||
{"آزمایشی", "xn--hgbk6aj7f53bba"},
|
||||
{"测试", "xn--0zwm56d"},
|
||||
{"測試", "xn--g6w251d"},
|
||||
{"испытание", "xn--80akhbyknj4f"},
|
||||
{"परीक्षा", "xn--11b5bs3a9aj6g"},
|
||||
{"δοκιμή", "xn--jxalpdlp"},
|
||||
{"테스트", "xn--9t4b11yi5a"},
|
||||
{"טעסט", "xn--deba0ad"},
|
||||
{"テスト", "xn--zckzah"},
|
||||
{"பரிட்சை", "xn--hlcj6aya9esc7a"},
|
||||
{"mamão-com-açúcar", "xn--mamo-com-acar-yeb1e6q"},
|
||||
{"σ", "xn--4xa"},
|
||||
}
|
||||
|
||||
func TestEncodeDecodePunycode(t *testing.T) {
|
||||
for _, tst := range testcases {
|
||||
enc := encode([]byte(tst[0]))
|
||||
if string(enc) != tst[1] {
|
||||
t.Errorf("%s encodeded as %s but should be %s", tst[0], enc, tst[1])
|
||||
}
|
||||
dec := decode([]byte(tst[1]))
|
||||
if string(dec) != strings.ToLower(tst[0]) {
|
||||
t.Errorf("%s decoded as %s but should be %s", tst[1], dec, strings.ToLower(tst[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToFromPunycode(t *testing.T) {
|
||||
for _, tst := range testcases {
|
||||
// assert unicode.com == punycode.com
|
||||
full := ToPunycode(tst[0] + ".com")
|
||||
if full != tst[1]+".com" {
|
||||
t.Errorf("invalid result from string conversion to punycode, %s and should be %s.com", full, tst[1])
|
||||
}
|
||||
// assert punycode.punycode == unicode.unicode
|
||||
decoded := FromPunycode(tst[1] + "." + tst[1])
|
||||
if decoded != strings.ToLower(tst[0]+"."+tst[0]) {
|
||||
t.Errorf("invalid result from string conversion to punycode, %s and should be %s.%s", decoded, tst[0], tst[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeFinalPeriod(t *testing.T) {
|
||||
for _, tst := range testcases {
|
||||
// assert unicode.com. == punycode.com.
|
||||
full := ToPunycode(tst[0] + ".")
|
||||
if full != tst[1]+"." {
|
||||
t.Errorf("invalid result from string conversion to punycode when period added at the end, %#v and should be %#v", full, tst[1]+".")
|
||||
}
|
||||
// assert punycode.com. == unicode.com.
|
||||
decoded := FromPunycode(tst[1] + ".")
|
||||
if decoded != strings.ToLower(tst[0]+".") {
|
||||
t.Errorf("invalid result from string conversion to punycode when period added, %#v and should be %#v", decoded, tst[0]+".")
|
||||
}
|
||||
full = ToPunycode(tst[0])
|
||||
if full != tst[1] {
|
||||
t.Errorf("invalid result from string conversion to punycode when no period added at the end, %#v and should be %#v", full, tst[1]+".")
|
||||
}
|
||||
// assert punycode.com. == unicode.com.
|
||||
decoded = FromPunycode(tst[1])
|
||||
if decoded != strings.ToLower(tst[0]) {
|
||||
t.Errorf("invalid result from string conversion to punycode when no period added, %#v and should be %#v", decoded, tst[0]+".")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var invalidACEs = []string{
|
||||
"xn--*",
|
||||
"xn--",
|
||||
"xn---",
|
||||
"xn--a000000000",
|
||||
}
|
||||
|
||||
func TestInvalidPunycode(t *testing.T) {
|
||||
for _, d := range invalidACEs {
|
||||
s := FromPunycode(d)
|
||||
if s != d {
|
||||
t.Errorf("Changed invalid name %s to %#v", d, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// You can verify the labels that are valid or not comparing to the Verisign
|
||||
// website: http://mct.verisign-grs.com/
|
||||
var invalidUnicodes = []string{
|
||||
"Σ",
|
||||
"ЯZ",
|
||||
"Испытание",
|
||||
}
|
||||
|
||||
func TestInvalidUnicodes(t *testing.T) {
|
||||
for _, d := range invalidUnicodes {
|
||||
s := ToPunycode(d)
|
||||
if s != "" {
|
||||
t.Errorf("Changed invalid name %s to %#v", d, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,12 +98,11 @@ func CountLabel(s string) (labels int) {
|
|||
return
|
||||
}
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// Split splits a name s into its label indexes.
|
||||
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
|
||||
// The root name (.) returns nil. Also see dns.SplitDomainName.
|
||||
// The root name (.) returns nil. Also see SplitDomainName.
|
||||
func Split(s string) []int {
|
||||
if s == "." {
|
||||
return nil
|
||||
|
|
@ -119,12 +118,12 @@ func Split(s string) []int {
|
|||
}
|
||||
idx = append(idx, off)
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// NextLabel returns the index of the start of the next label in the
|
||||
// string s starting at offset.
|
||||
// The bool end is true when the end of the string has been reached.
|
||||
// Also see PrevLabel.
|
||||
func NextLabel(s string, offset int) (i int, end bool) {
|
||||
quote := false
|
||||
for i = offset; i < len(s)-1; i++ {
|
||||
|
|
@ -147,6 +146,7 @@ func NextLabel(s string, offset int) (i int, end bool) {
|
|||
// PrevLabel returns the index of the label when starting from the right and
|
||||
// jumping n labels to the left.
|
||||
// The bool start is true when the start of the string has been overshot.
|
||||
// Also see NextLabel.
|
||||
func PrevLabel(s string, n int) (i int, start bool) {
|
||||
if n == 0 {
|
||||
return len(s), false
|
||||
|
|
|
|||
|
|
@ -1,199 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareDomainName(t *testing.T) {
|
||||
s1 := "www.miek.nl."
|
||||
s2 := "miek.nl."
|
||||
s3 := "www.bla.nl."
|
||||
s4 := "nl.www.bla."
|
||||
s5 := "nl"
|
||||
s6 := "miek.nl"
|
||||
|
||||
if CompareDomainName(s1, s2) != 2 {
|
||||
t.Errorf("%s with %s should be %d", s1, s2, 2)
|
||||
}
|
||||
if CompareDomainName(s1, s3) != 1 {
|
||||
t.Errorf("%s with %s should be %d", s1, s3, 1)
|
||||
}
|
||||
if CompareDomainName(s3, s4) != 0 {
|
||||
t.Errorf("%s with %s should be %d", s3, s4, 0)
|
||||
}
|
||||
// Non qualified tests
|
||||
if CompareDomainName(s1, s5) != 1 {
|
||||
t.Errorf("%s with %s should be %d", s1, s5, 1)
|
||||
}
|
||||
if CompareDomainName(s1, s6) != 2 {
|
||||
t.Errorf("%s with %s should be %d", s1, s5, 2)
|
||||
}
|
||||
|
||||
if CompareDomainName(s1, ".") != 0 {
|
||||
t.Errorf("%s with %s should be %d", s1, s5, 0)
|
||||
}
|
||||
if CompareDomainName(".", ".") != 0 {
|
||||
t.Errorf("%s with %s should be %d", ".", ".", 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplit(t *testing.T) {
|
||||
splitter := map[string]int{
|
||||
"www.miek.nl.": 3,
|
||||
"www.miek.nl": 3,
|
||||
"www..miek.nl": 4,
|
||||
`www\.miek.nl.`: 2,
|
||||
`www\\.miek.nl.`: 3,
|
||||
".": 0,
|
||||
"nl.": 1,
|
||||
"nl": 1,
|
||||
"com.": 1,
|
||||
".com.": 2,
|
||||
}
|
||||
for s, i := range splitter {
|
||||
if x := len(Split(s)); x != i {
|
||||
t.Errorf("labels should be %d, got %d: %s %v", i, x, s, Split(s))
|
||||
} else {
|
||||
t.Logf("%s %v", s, Split(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplit2(t *testing.T) {
|
||||
splitter := map[string][]int{
|
||||
"www.miek.nl.": []int{0, 4, 9},
|
||||
"www.miek.nl": []int{0, 4, 9},
|
||||
"nl": []int{0},
|
||||
}
|
||||
for s, i := range splitter {
|
||||
x := Split(s)
|
||||
switch len(i) {
|
||||
case 1:
|
||||
if x[0] != i[0] {
|
||||
t.Errorf("labels should be %v, got %v: %s", i, x, s)
|
||||
}
|
||||
default:
|
||||
if x[0] != i[0] || x[1] != i[1] || x[2] != i[2] {
|
||||
t.Errorf("labels should be %v, got %v: %s", i, x, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevLabel(t *testing.T) {
|
||||
type prev struct {
|
||||
string
|
||||
int
|
||||
}
|
||||
prever := map[prev]int{
|
||||
prev{"www.miek.nl.", 0}: 12,
|
||||
prev{"www.miek.nl.", 1}: 9,
|
||||
prev{"www.miek.nl.", 2}: 4,
|
||||
|
||||
prev{"www.miek.nl", 0}: 11,
|
||||
prev{"www.miek.nl", 1}: 9,
|
||||
prev{"www.miek.nl", 2}: 4,
|
||||
|
||||
prev{"www.miek.nl.", 5}: 0,
|
||||
prev{"www.miek.nl", 5}: 0,
|
||||
|
||||
prev{"www.miek.nl.", 3}: 0,
|
||||
prev{"www.miek.nl", 3}: 0,
|
||||
}
|
||||
for s, i := range prever {
|
||||
x, ok := PrevLabel(s.string, s.int)
|
||||
if i != x {
|
||||
t.Errorf("label should be %d, got %d, %t: preving %d, %s", i, x, ok, s.int, s.string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountLabel(t *testing.T) {
|
||||
splitter := map[string]int{
|
||||
"www.miek.nl.": 3,
|
||||
"www.miek.nl": 3,
|
||||
"nl": 1,
|
||||
".": 0,
|
||||
}
|
||||
for s, i := range splitter {
|
||||
x := CountLabel(s)
|
||||
if x != i {
|
||||
t.Errorf("CountLabel should have %d, got %d", i, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitDomainName(t *testing.T) {
|
||||
labels := map[string][]string{
|
||||
"miek.nl": []string{"miek", "nl"},
|
||||
".": nil,
|
||||
"www.miek.nl.": []string{"www", "miek", "nl"},
|
||||
"www.miek.nl": []string{"www", "miek", "nl"},
|
||||
"www..miek.nl": []string{"www", "", "miek", "nl"},
|
||||
`www\.miek.nl`: []string{`www\.miek`, "nl"},
|
||||
`www\\.miek.nl`: []string{`www\\`, "miek", "nl"},
|
||||
}
|
||||
domainLoop:
|
||||
for domain, splits := range labels {
|
||||
parts := SplitDomainName(domain)
|
||||
if len(parts) != len(splits) {
|
||||
t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
|
||||
continue domainLoop
|
||||
}
|
||||
for i := range parts {
|
||||
if parts[i] != splits[i] {
|
||||
t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits)
|
||||
continue domainLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDomainName(t *testing.T) {
|
||||
type ret struct {
|
||||
ok bool
|
||||
lab int
|
||||
}
|
||||
names := map[string]*ret{
|
||||
"..": &ret{false, 1},
|
||||
"@.": &ret{true, 1},
|
||||
"www.example.com": &ret{true, 3},
|
||||
"www.e%ample.com": &ret{true, 3},
|
||||
"www.example.com.": &ret{true, 3},
|
||||
"mi\\k.nl.": &ret{true, 2},
|
||||
"mi\\k.nl": &ret{true, 2},
|
||||
}
|
||||
for d, ok := range names {
|
||||
l, k := IsDomainName(d)
|
||||
if ok.ok != k || ok.lab != l {
|
||||
t.Errorf(" got %v %d for %s ", k, l, d)
|
||||
t.Errorf("have %v %d for %s ", ok.ok, ok.lab, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSplitLabels(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Split("www.example.com")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLenLabels(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
CountLabel("www.example.com")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompareLabels(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
CompareDomainName("www.example.com", "aa.example.com")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsSubDomain(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsSubDomain("www.example.com", "aa.example.com")
|
||||
IsSubDomain("example.com", "aa.example.com")
|
||||
IsSubDomain("miek.nl", "aa.example.com")
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,8 @@ var (
|
|||
// ErrFqdn indicates that a domain name does not have a closing dot.
|
||||
ErrFqdn error = &Error{err: "domain must be fully qualified"}
|
||||
// ErrId indicates there is a mismatch with the message's ID.
|
||||
ErrId error = &Error{err: "id mismatch"}
|
||||
ErrId error = &Error{err: "id mismatch"}
|
||||
// ErrKeyAlg indicates that the algorithm in the key is not valid.
|
||||
ErrKeyAlg error = &Error{err: "bad key algorithm"}
|
||||
ErrKey error = &Error{err: "bad key"}
|
||||
ErrKeySize error = &Error{err: "bad key size"}
|
||||
|
|
@ -53,6 +54,9 @@ var (
|
|||
ErrSoa error = &Error{err: "no SOA"}
|
||||
// ErrTime indicates a timing error in TSIG authentication.
|
||||
ErrTime error = &Error{err: "bad time"}
|
||||
// ErrTruncated indicates that we failed to unpack a truncated message.
|
||||
// We unpacked as much as we had so Msg can still be used, if desired.
|
||||
ErrTruncated error = &Error{err: "failed to unpack truncated message"}
|
||||
)
|
||||
|
||||
// Id, by default, returns a 16 bits random number to be used as a
|
||||
|
|
@ -88,84 +92,6 @@ type Msg struct {
|
|||
Extra []RR // Holds the RR(s) of the additional section.
|
||||
}
|
||||
|
||||
// TypeToString is a map of strings for each RR wire type.
|
||||
var TypeToString = map[uint16]string{
|
||||
TypeA: "A",
|
||||
TypeAAAA: "AAAA",
|
||||
TypeAFSDB: "AFSDB",
|
||||
TypeANY: "ANY", // Meta RR
|
||||
TypeATMA: "ATMA",
|
||||
TypeAXFR: "AXFR", // Meta RR
|
||||
TypeCAA: "CAA",
|
||||
TypeCDNSKEY: "CDNSKEY",
|
||||
TypeCDS: "CDS",
|
||||
TypeCERT: "CERT",
|
||||
TypeCNAME: "CNAME",
|
||||
TypeDHCID: "DHCID",
|
||||
TypeDLV: "DLV",
|
||||
TypeDNAME: "DNAME",
|
||||
TypeDNSKEY: "DNSKEY",
|
||||
TypeDS: "DS",
|
||||
TypeEID: "EID",
|
||||
TypeEUI48: "EUI48",
|
||||
TypeEUI64: "EUI64",
|
||||
TypeGID: "GID",
|
||||
TypeGPOS: "GPOS",
|
||||
TypeHINFO: "HINFO",
|
||||
TypeHIP: "HIP",
|
||||
TypeIPSECKEY: "IPSECKEY",
|
||||
TypeISDN: "ISDN",
|
||||
TypeIXFR: "IXFR", // Meta RR
|
||||
TypeKEY: "KEY",
|
||||
TypeKX: "KX",
|
||||
TypeL32: "L32",
|
||||
TypeL64: "L64",
|
||||
TypeLOC: "LOC",
|
||||
TypeLP: "LP",
|
||||
TypeMB: "MB",
|
||||
TypeMD: "MD",
|
||||
TypeMF: "MF",
|
||||
TypeMG: "MG",
|
||||
TypeMINFO: "MINFO",
|
||||
TypeMR: "MR",
|
||||
TypeMX: "MX",
|
||||
TypeNAPTR: "NAPTR",
|
||||
TypeNID: "NID",
|
||||
TypeNINFO: "NINFO",
|
||||
TypeNIMLOC: "NIMLOC",
|
||||
TypeNS: "NS",
|
||||
TypeNSAPPTR: "NSAP-PTR",
|
||||
TypeNSEC3: "NSEC3",
|
||||
TypeNSEC3PARAM: "NSEC3PARAM",
|
||||
TypeNSEC: "NSEC",
|
||||
TypeNULL: "NULL",
|
||||
TypeOPT: "OPT",
|
||||
TypeOPENPGPKEY: "OPENPGPKEY",
|
||||
TypePTR: "PTR",
|
||||
TypeRKEY: "RKEY",
|
||||
TypeRP: "RP",
|
||||
TypeRRSIG: "RRSIG",
|
||||
TypeRT: "RT",
|
||||
TypeSIG: "SIG",
|
||||
TypeSOA: "SOA",
|
||||
TypeSPF: "SPF",
|
||||
TypeSRV: "SRV",
|
||||
TypeSSHFP: "SSHFP",
|
||||
TypeTA: "TA",
|
||||
TypeTALINK: "TALINK",
|
||||
TypeTKEY: "TKEY", // Meta RR
|
||||
TypeTLSA: "TLSA",
|
||||
TypeTSIG: "TSIG", // Meta RR
|
||||
TypeTXT: "TXT",
|
||||
TypePX: "PX",
|
||||
TypeUID: "UID",
|
||||
TypeUINFO: "UINFO",
|
||||
TypeUNSPEC: "UNSPEC",
|
||||
TypeURI: "URI",
|
||||
TypeWKS: "WKS",
|
||||
TypeX25: "X25",
|
||||
}
|
||||
|
||||
// StringToType is the reverse of TypeToString, needed for string parsing.
|
||||
var StringToType = reverseInt16(TypeToString)
|
||||
|
||||
|
|
@ -1315,8 +1241,8 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
|||
continue
|
||||
}
|
||||
}
|
||||
if off == lenmsg {
|
||||
// zero rdata foo, OK for dyn. updates
|
||||
if off == lenmsg && int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) == 0 {
|
||||
// zero rdata is ok for dyn updates, but only if rdlength is 0
|
||||
break
|
||||
}
|
||||
s, off, err = UnpackDomainName(msg, off)
|
||||
|
|
@ -1460,7 +1386,7 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
|||
}
|
||||
end := off + int(h.Rdlength)
|
||||
// make an rr of that type and re-unpack.
|
||||
mk, known := typeToRR[h.Rrtype]
|
||||
mk, known := TypeToRR[h.Rrtype]
|
||||
if !known {
|
||||
rr = new(RFC3597)
|
||||
} else {
|
||||
|
|
@ -1473,6 +1399,32 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
|
|||
return rr, off, err
|
||||
}
|
||||
|
||||
// unpackRRslice unpacks msg[off:] into an []RR.
|
||||
// If we cannot unpack the whole array, then it will return nil
|
||||
func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
|
||||
var r RR
|
||||
// Optimistically make dst be the length that was sent
|
||||
dst := make([]RR, 0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
off1 := off
|
||||
r, off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
off = len(msg)
|
||||
break
|
||||
}
|
||||
// If offset does not increase anymore, l is a lie
|
||||
if off1 == off {
|
||||
l = i
|
||||
break
|
||||
}
|
||||
dst = append(dst, r)
|
||||
}
|
||||
if err != nil && off == len(msg) {
|
||||
dst = nil
|
||||
}
|
||||
return dst, off, err
|
||||
}
|
||||
|
||||
// Reverse a map
|
||||
func reverseInt8(m map[uint8]string) map[string]uint8 {
|
||||
n := make(map[string]uint8)
|
||||
|
|
@ -1671,84 +1623,48 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
|||
dns.CheckingDisabled = (dh.Bits & _CD) != 0
|
||||
dns.Rcode = int(dh.Bits & 0xF)
|
||||
|
||||
// Don't pre-alloc these arrays, the incoming lengths are from the network.
|
||||
dns.Question = make([]Question, 0, 1)
|
||||
dns.Answer = make([]RR, 0, 10)
|
||||
dns.Ns = make([]RR, 0, 10)
|
||||
dns.Extra = make([]RR, 0, 10)
|
||||
// Optimistically use the count given to us in the header
|
||||
dns.Question = make([]Question, 0, int(dh.Qdcount))
|
||||
|
||||
var q Question
|
||||
for i := 0; i < int(dh.Qdcount); i++ {
|
||||
off1 := off
|
||||
off, err = UnpackStruct(&q, msg, off)
|
||||
if err != nil {
|
||||
// Even if Truncated is set, we only will set ErrTruncated if we
|
||||
// actually got the questions
|
||||
return err
|
||||
}
|
||||
if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
|
||||
dh.Qdcount = uint16(i)
|
||||
break
|
||||
}
|
||||
|
||||
dns.Question = append(dns.Question, q)
|
||||
|
||||
}
|
||||
// If we see a TC bit being set we return here, without
|
||||
// an error, because technically it isn't an error. So return
|
||||
// without parsing the potentially corrupt packet and hitting an error.
|
||||
// TODO(miek): this isn't the best strategy!
|
||||
// Better stragey would be: set boolean indicating truncated message, go forth and parse
|
||||
// until we hit an error, return the message without the latest parsed rr if this boolean
|
||||
// is true.
|
||||
if dns.Truncated {
|
||||
dns.Answer = nil
|
||||
dns.Ns = nil
|
||||
dns.Extra = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
var r RR
|
||||
for i := 0; i < int(dh.Ancount); i++ {
|
||||
off1 := off
|
||||
r, off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if off1 == off { // Offset does not increase anymore, dh.Ancount is a lie!
|
||||
dh.Ancount = uint16(i)
|
||||
break
|
||||
}
|
||||
dns.Answer = append(dns.Answer, r)
|
||||
dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off)
|
||||
// The header counts might have been wrong so we need to update it
|
||||
dh.Ancount = uint16(len(dns.Answer))
|
||||
if err == nil {
|
||||
dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off)
|
||||
}
|
||||
for i := 0; i < int(dh.Nscount); i++ {
|
||||
off1 := off
|
||||
r, off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if off1 == off { // Offset does not increase anymore, dh.Nscount is a lie!
|
||||
dh.Nscount = uint16(i)
|
||||
break
|
||||
}
|
||||
dns.Ns = append(dns.Ns, r)
|
||||
}
|
||||
for i := 0; i < int(dh.Arcount); i++ {
|
||||
off1 := off
|
||||
r, off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if off1 == off { // Offset does not increase anymore, dh.Arcount is a lie!
|
||||
dh.Arcount = uint16(i)
|
||||
break
|
||||
}
|
||||
dns.Extra = append(dns.Extra, r)
|
||||
// The header counts might have been wrong so we need to update it
|
||||
dh.Nscount = uint16(len(dns.Ns))
|
||||
if err == nil {
|
||||
dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off)
|
||||
}
|
||||
// The header counts might have been wrong so we need to update it
|
||||
dh.Arcount = uint16(len(dns.Extra))
|
||||
if off != len(msg) {
|
||||
// TODO(miek) make this an error?
|
||||
// use PackOpt to let people tell how detailed the error reporting should be?
|
||||
// println("dns: extra bytes in dns packet", off, "<", len(msg))
|
||||
} else if dns.Truncated {
|
||||
// Whether we ran into a an error or not, we want to return that it
|
||||
// was truncated
|
||||
err = ErrTruncated
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert a complete message to a string with dig-like output.
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPackNsec3(t *testing.T) {
|
||||
nsec3 := HashName("dnsex.nl.", SHA1, 0, "DEAD")
|
||||
if nsec3 != "ROCCJAE8BJJU7HN6T7NG3TNM8ACRS87J" {
|
||||
t.Error(nsec3)
|
||||
}
|
||||
|
||||
nsec3 = HashName("a.b.c.example.org.", SHA1, 2, "DEAD")
|
||||
if nsec3 != "6LQ07OAHBTOOEU2R9ANI2AT70K5O0RCG" {
|
||||
t.Error(nsec3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNsec3(t *testing.T) {
|
||||
// examples taken from .nl
|
||||
nsec3, _ := NewRR("39p91242oslggest5e6a7cci4iaeqvnk.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6 NS DS RRSIG")
|
||||
if !nsec3.(*NSEC3).Cover("snasajsksasasa.nl.") { // 39p94jrinub66hnpem8qdpstrec86pg3
|
||||
t.Error("39p94jrinub66hnpem8qdpstrec86pg3. should be covered by 39p91242oslggest5e6a7cci4iaeqvnk.nl. - 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6")
|
||||
}
|
||||
nsec3, _ = NewRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
|
||||
if !nsec3.(*NSEC3).Match("nl.") { // sk4e8fj94u78smusb40o1n0oltbblu2r.nl.
|
||||
t.Error("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -33,7 +33,7 @@ type PrivateRR struct {
|
|||
|
||||
func mkPrivateRR(rrtype uint16) *PrivateRR {
|
||||
// Panics if RR is not an instance of PrivateRR.
|
||||
rrfunc, ok := typeToRR[rrtype]
|
||||
rrfunc, ok := TypeToRR[rrtype]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
|
||||
}
|
||||
|
|
@ -43,11 +43,13 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
|
|||
case *PrivateRR:
|
||||
return rr
|
||||
}
|
||||
panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr))
|
||||
panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
|
||||
}
|
||||
|
||||
// Header return the RR header of r.
|
||||
func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
|
||||
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
|
||||
|
||||
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
|
||||
|
||||
// Private len and copy parts to satisfy RR interface.
|
||||
func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
|
||||
|
|
@ -69,7 +71,7 @@ func (r *PrivateRR) copy() RR {
|
|||
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
||||
rtypestr = strings.ToUpper(rtypestr)
|
||||
|
||||
typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
||||
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
||||
TypeToString[rtype] = rtypestr
|
||||
StringToType[rtypestr] = rtype
|
||||
|
||||
|
|
@ -106,7 +108,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
|
|||
func PrivateHandleRemove(rtype uint16) {
|
||||
rtypestr, ok := TypeToString[rtype]
|
||||
if ok {
|
||||
delete(typeToRR, rtype)
|
||||
delete(TypeToRR, rtype)
|
||||
delete(TypeToString, rtype)
|
||||
delete(typeToparserFunc, rtype)
|
||||
delete(StringToType, rtypestr)
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
package dns_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const TypeISBN uint16 = 0x0F01
|
||||
|
||||
// A crazy new RR type :)
|
||||
type ISBN struct {
|
||||
x string // rdata with 10 or 13 numbers, dashes or spaces allowed
|
||||
}
|
||||
|
||||
func NewISBN() dns.PrivateRdata { return &ISBN{""} }
|
||||
|
||||
func (rd *ISBN) Len() int { return len([]byte(rd.x)) }
|
||||
func (rd *ISBN) String() string { return rd.x }
|
||||
|
||||
func (rd *ISBN) Parse(txt []string) error {
|
||||
rd.x = strings.TrimSpace(strings.Join(txt, " "))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rd *ISBN) Pack(buf []byte) (int, error) {
|
||||
b := []byte(rd.x)
|
||||
n := copy(buf, b)
|
||||
if n != len(b) {
|
||||
return n, dns.ErrBuf
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (rd *ISBN) Unpack(buf []byte) (int, error) {
|
||||
rd.x = string(buf)
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func (rd *ISBN) Copy(dest dns.PrivateRdata) error {
|
||||
isbn, ok := dest.(*ISBN)
|
||||
if !ok {
|
||||
return dns.ErrRdata
|
||||
}
|
||||
isbn.x = rd.x
|
||||
return nil
|
||||
}
|
||||
|
||||
var testrecord = strings.Join([]string{"example.org.", "3600", "IN", "ISBN", "12-3 456789-0-123"}, "\t")
|
||||
|
||||
func TestPrivateText(t *testing.T) {
|
||||
dns.PrivateHandle("ISBN", TypeISBN, NewISBN)
|
||||
defer dns.PrivateHandleRemove(TypeISBN)
|
||||
|
||||
rr, err := dns.NewRR(testrecord)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rr.String() != testrecord {
|
||||
t.Errorf("record string representation did not match original %#v != %#v", rr.String(), testrecord)
|
||||
} else {
|
||||
t.Log(rr.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateByteSlice(t *testing.T) {
|
||||
dns.PrivateHandle("ISBN", TypeISBN, NewISBN)
|
||||
defer dns.PrivateHandleRemove(TypeISBN)
|
||||
|
||||
rr, err := dns.NewRR(testrecord)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 100)
|
||||
off, err := dns.PackRR(rr, buf, 0, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("got error packing ISBN: %v", err)
|
||||
}
|
||||
|
||||
custrr := rr.(*dns.PrivateRR)
|
||||
if ln := custrr.Data.Len() + len(custrr.Header().Name) + 11; ln != off {
|
||||
t.Errorf("offset is not matching to length of Private RR: %d!=%d", off, ln)
|
||||
}
|
||||
|
||||
rr1, off1, err := dns.UnpackRR(buf[:off], 0)
|
||||
if err != nil {
|
||||
t.Errorf("got error unpacking ISBN: %v", err)
|
||||
}
|
||||
|
||||
if off1 != off {
|
||||
t.Errorf("Offset after unpacking differs: %d != %d", off1, off)
|
||||
}
|
||||
|
||||
if rr1.String() != testrecord {
|
||||
t.Errorf("Record string representation did not match original %#v != %#v", rr1.String(), testrecord)
|
||||
} else {
|
||||
t.Log(rr1.String())
|
||||
}
|
||||
}
|
||||
|
||||
const TypeVERSION uint16 = 0x0F02
|
||||
|
||||
type VERSION struct {
|
||||
x string
|
||||
}
|
||||
|
||||
func NewVersion() dns.PrivateRdata { return &VERSION{""} }
|
||||
|
||||
func (rd *VERSION) String() string { return rd.x }
|
||||
func (rd *VERSION) Parse(txt []string) error {
|
||||
rd.x = strings.TrimSpace(strings.Join(txt, " "))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rd *VERSION) Pack(buf []byte) (int, error) {
|
||||
b := []byte(rd.x)
|
||||
n := copy(buf, b)
|
||||
if n != len(b) {
|
||||
return n, dns.ErrBuf
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (rd *VERSION) Unpack(buf []byte) (int, error) {
|
||||
rd.x = string(buf)
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func (rd *VERSION) Copy(dest dns.PrivateRdata) error {
|
||||
isbn, ok := dest.(*VERSION)
|
||||
if !ok {
|
||||
return dns.ErrRdata
|
||||
}
|
||||
isbn.x = rd.x
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rd *VERSION) Len() int {
|
||||
return len([]byte(rd.x))
|
||||
}
|
||||
|
||||
var smallzone = `$ORIGIN example.org.
|
||||
@ SOA sns.dns.icann.org. noc.dns.icann.org. (
|
||||
2014091518 7200 3600 1209600 3600
|
||||
)
|
||||
A 1.2.3.4
|
||||
ok ISBN 1231-92110-12
|
||||
go VERSION (
|
||||
1.3.1 ; comment
|
||||
)
|
||||
www ISBN 1231-92110-16
|
||||
* CNAME @
|
||||
`
|
||||
|
||||
func TestPrivateZoneParser(t *testing.T) {
|
||||
dns.PrivateHandle("ISBN", TypeISBN, NewISBN)
|
||||
dns.PrivateHandle("VERSION", TypeVERSION, NewVersion)
|
||||
defer dns.PrivateHandleRemove(TypeISBN)
|
||||
defer dns.PrivateHandleRemove(TypeVERSION)
|
||||
|
||||
r := strings.NewReader(smallzone)
|
||||
for x := range dns.ParseZone(r, ".", "") {
|
||||
if err := x.Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(x.RR)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package dns
|
||||
|
||||
// Dedup removes identical RRs from rrs. It preserves the original ordering.
|
||||
// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
|
||||
// rrs.
|
||||
// m is used to store the RRs temporay. If it is nil a new map will be allocated.
|
||||
func Dedup(rrs []RR, m map[string]RR) []RR {
|
||||
if m == nil {
|
||||
m = make(map[string]RR)
|
||||
}
|
||||
// Save the keys, so we don't have to call normalizedString twice.
|
||||
keys := make([]*string, 0, len(rrs))
|
||||
|
||||
for _, r := range rrs {
|
||||
key := normalizedString(r)
|
||||
keys = append(keys, &key)
|
||||
if _, ok := m[key]; ok {
|
||||
// Shortest TTL wins.
|
||||
if m[key].Header().Ttl > r.Header().Ttl {
|
||||
m[key].Header().Ttl = r.Header().Ttl
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
m[key] = r
|
||||
}
|
||||
// If the length of the result map equals the amount of RRs we got,
|
||||
// it means they were all different. We can then just return the original rrset.
|
||||
if len(m) == len(rrs) {
|
||||
return rrs
|
||||
}
|
||||
|
||||
j := 0
|
||||
for i, r := range rrs {
|
||||
// If keys[i] lives in the map, we should copy and remove it.
|
||||
if _, ok := m[*keys[i]]; ok {
|
||||
delete(m, *keys[i])
|
||||
rrs[j] = r
|
||||
j++
|
||||
}
|
||||
|
||||
if len(m) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return rrs[:j]
|
||||
}
|
||||
|
||||
// normalizedString returns a normalized string from r. The TTL
|
||||
// is removed and the domain name is lowercased. We go from this:
|
||||
// DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to:
|
||||
// lowercasename<TAB>CLASS<TAB>TYPE...
|
||||
func normalizedString(r RR) string {
|
||||
// A string Go DNS makes has: domainname<TAB>TTL<TAB>...
|
||||
b := []byte(r.String())
|
||||
|
||||
// find the first non-escaped tab, then another, so we capture where the TTL lives.
|
||||
esc := false
|
||||
ttlStart, ttlEnd := 0, 0
|
||||
for i := 0; i < len(b) && ttlEnd == 0; i++ {
|
||||
switch {
|
||||
case b[i] == '\\':
|
||||
esc = !esc
|
||||
case b[i] == '\t' && !esc:
|
||||
if ttlStart == 0 {
|
||||
ttlStart = i
|
||||
continue
|
||||
}
|
||||
if ttlEnd == 0 {
|
||||
ttlEnd = i
|
||||
}
|
||||
case b[i] >= 'A' && b[i] <= 'Z' && !esc:
|
||||
b[i] += 32
|
||||
default:
|
||||
esc = false
|
||||
}
|
||||
}
|
||||
|
||||
// remove TTL.
|
||||
copy(b[ttlStart:], b[ttlEnd:])
|
||||
cut := ttlEnd - ttlStart
|
||||
return string(b[:len(b)-cut])
|
||||
}
|
||||
|
|
@ -10,6 +10,9 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// Maximum number of TCP queries before we close the socket.
|
||||
const maxTCPQueries = 128
|
||||
|
||||
// Handler is implemented by any value that implements ServeDNS.
|
||||
type Handler interface {
|
||||
ServeDNS(w ResponseWriter, r *Msg)
|
||||
|
|
@ -159,9 +162,9 @@ func (mux *ServeMux) HandleRemove(pattern string) {
|
|||
if pattern == "" {
|
||||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
// don't need a mutex here, because deleting is OK, even if the
|
||||
// entry is note there.
|
||||
mux.m.Lock()
|
||||
delete(mux.z, Fqdn(pattern))
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// ServeDNS dispatches the request to the handler whose
|
||||
|
|
@ -268,27 +271,21 @@ type Server struct {
|
|||
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||
DecorateWriter DecorateWriter
|
||||
|
||||
// For graceful shutdown.
|
||||
stopUDP chan bool
|
||||
stopTCP chan bool
|
||||
wgUDP sync.WaitGroup
|
||||
wgTCP sync.WaitGroup
|
||||
// Graceful shutdown handling
|
||||
|
||||
// make start/shutdown not racy
|
||||
lock sync.Mutex
|
||||
inFlight sync.WaitGroup
|
||||
|
||||
lock sync.RWMutex
|
||||
started bool
|
||||
}
|
||||
|
||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||
func (srv *Server) ListenAndServe() error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
if srv.started {
|
||||
srv.lock.Unlock()
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
defer srv.lock.Unlock()
|
||||
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
|
||||
srv.started = true
|
||||
addr := srv.Addr
|
||||
if addr == "" {
|
||||
addr = ":domain"
|
||||
|
|
@ -307,7 +304,11 @@ func (srv *Server) ListenAndServe() error {
|
|||
return e
|
||||
}
|
||||
srv.Listener = l
|
||||
return srv.serveTCP(l)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveTCP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
case "udp", "udp4", "udp6":
|
||||
a, e := net.ResolveUDPAddr(srv.Net, addr)
|
||||
if e != nil {
|
||||
|
|
@ -321,7 +322,11 @@ func (srv *Server) ListenAndServe() error {
|
|||
return e
|
||||
}
|
||||
srv.PacketConn = l
|
||||
return srv.serveUDP(l)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveUDP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
return &Error{err: "bad network"}
|
||||
}
|
||||
|
|
@ -330,15 +335,12 @@ func (srv *Server) ListenAndServe() error {
|
|||
// configured in *Server. Its main use is to start a server from systemd.
|
||||
func (srv *Server) ActivateAndServe() error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
if srv.started {
|
||||
srv.lock.Unlock()
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
|
||||
srv.started = true
|
||||
pConn := srv.PacketConn
|
||||
l := srv.Listener
|
||||
srv.lock.Unlock()
|
||||
if pConn != nil {
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
|
|
@ -347,12 +349,20 @@ func (srv *Server) ActivateAndServe() error {
|
|||
if e := setUDPSocketOptions(t); e != nil {
|
||||
return e
|
||||
}
|
||||
return srv.serveUDP(t)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e := srv.serveUDP(t)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
}
|
||||
if l != nil {
|
||||
if t, ok := l.(*net.TCPListener); ok {
|
||||
return srv.serveTCP(t)
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e := srv.serveTCP(t)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
}
|
||||
return &Error{err: "bad listeners"}
|
||||
|
|
@ -369,36 +379,20 @@ func (srv *Server) Shutdown() error {
|
|||
return &Error{err: "server not started"}
|
||||
}
|
||||
srv.started = false
|
||||
net, addr := srv.Net, srv.Addr
|
||||
switch {
|
||||
case srv.Listener != nil:
|
||||
a := srv.Listener.Addr()
|
||||
net, addr = a.Network(), a.String()
|
||||
case srv.PacketConn != nil:
|
||||
a := srv.PacketConn.LocalAddr()
|
||||
net, addr = a.Network(), a.String()
|
||||
}
|
||||
srv.lock.Unlock()
|
||||
|
||||
fin := make(chan bool)
|
||||
switch net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
go func() {
|
||||
srv.stopTCP <- true
|
||||
srv.wgTCP.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
|
||||
case "udp", "udp4", "udp6":
|
||||
go func() {
|
||||
srv.stopUDP <- true
|
||||
srv.wgUDP.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
if srv.PacketConn != nil {
|
||||
srv.PacketConn.Close()
|
||||
}
|
||||
if srv.Listener != nil {
|
||||
srv.Listener.Close()
|
||||
}
|
||||
|
||||
c := &Client{Net: net}
|
||||
go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
|
||||
fin := make(chan bool)
|
||||
go func() {
|
||||
srv.inFlight.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(srv.getReadTimeout()):
|
||||
|
|
@ -440,21 +434,24 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
|
|||
for {
|
||||
rw, e := l.AcceptTCP()
|
||||
if e != nil {
|
||||
continue
|
||||
if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
|
||||
continue
|
||||
}
|
||||
return e
|
||||
}
|
||||
m, e := reader.ReadTCP(rw, rtimeout)
|
||||
select {
|
||||
case <-srv.stopTCP:
|
||||
srv.lock.RLock()
|
||||
if !srv.started {
|
||||
srv.lock.RUnlock()
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
srv.lock.RUnlock()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
srv.wgTCP.Add(1)
|
||||
srv.inFlight.Add(1)
|
||||
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// serveUDP starts a UDP listener for the server.
|
||||
|
|
@ -479,22 +476,24 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
// deadline is not used here
|
||||
for {
|
||||
m, s, e := reader.ReadUDP(l, rtimeout)
|
||||
select {
|
||||
case <-srv.stopUDP:
|
||||
srv.lock.RLock()
|
||||
if !srv.started {
|
||||
srv.lock.RUnlock()
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
srv.lock.RUnlock()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
srv.wgUDP.Add(1)
|
||||
srv.inFlight.Add(1)
|
||||
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// Serve a new connection.
|
||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t *net.TCPConn) {
|
||||
defer srv.inFlight.Done()
|
||||
|
||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
|
|
@ -502,15 +501,7 @@ func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *Ses
|
|||
w.writer = w
|
||||
}
|
||||
|
||||
q := 0
|
||||
defer func() {
|
||||
if u != nil {
|
||||
srv.wgUDP.Done()
|
||||
}
|
||||
if t != nil {
|
||||
srv.wgTCP.Done()
|
||||
}
|
||||
}()
|
||||
q := 0 // counter for the amount of TCP queries we get
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
|
|
@ -544,6 +535,12 @@ Redo:
|
|||
h.ServeDNS(w, req) // Writes back to the client
|
||||
|
||||
Exit:
|
||||
// TODO(miek): make this number configurable?
|
||||
if q > maxTCPQueries { // close socket after this many queries
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if w.hijacked {
|
||||
return // client calls Close()
|
||||
}
|
||||
|
|
@ -558,11 +555,6 @@ Exit:
|
|||
m, e := reader.ReadTCP(w.tcp, idleTimeout)
|
||||
if e == nil {
|
||||
q++
|
||||
// TODO(miek): make this number configurable?
|
||||
if q > 128 { // close socket after this many queries
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
goto Redo
|
||||
}
|
||||
w.Close()
|
||||
|
|
|
|||
|
|
@ -1,450 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func HelloServer(w ResponseWriter, req *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetReply(req)
|
||||
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func HelloServerBadId(w ResponseWriter, req *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetReply(req)
|
||||
m.Id += 1
|
||||
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func AnotherHelloServer(w ResponseWriter, req *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetReply(req)
|
||||
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func RunLocalUDPServer(laddr string) (*Server, string, error) {
|
||||
pc, err := net.ListenPacket("udp", laddr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
server := &Server{PacketConn: pc}
|
||||
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
server.NotifyStartedFunc = waitLock.Unlock
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
pc.Close()
|
||||
}()
|
||||
|
||||
waitLock.Lock()
|
||||
return server, pc.LocalAddr().String(), nil
|
||||
}
|
||||
|
||||
func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
|
||||
pc, err := net.ListenPacket("udp", laddr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
server := &Server{PacketConn: pc, Unsafe: true}
|
||||
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
server.NotifyStartedFunc = waitLock.Unlock
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
pc.Close()
|
||||
}()
|
||||
|
||||
waitLock.Lock()
|
||||
return server, pc.LocalAddr().String(), nil
|
||||
}
|
||||
|
||||
func RunLocalTCPServer(laddr string) (*Server, string, error) {
|
||||
l, err := net.Listen("tcp", laddr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
server := &Server{Listener: l}
|
||||
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
server.NotifyStartedFunc = waitLock.Unlock
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
l.Close()
|
||||
}()
|
||||
|
||||
waitLock.Lock()
|
||||
return server, l.Addr().String(), nil
|
||||
}
|
||||
|
||||
func TestServing(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
HandleFunc("example.com.", AnotherHelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
defer HandleRemove("example.com.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeTXT)
|
||||
r, _, err := c.Exchange(m, addrstr)
|
||||
if err != nil || len(r.Extra) == 0 {
|
||||
t.Fatal("failed to exchange miek.nl", err)
|
||||
}
|
||||
txt := r.Extra[0].(*TXT).Txt[0]
|
||||
if txt != "Hello world" {
|
||||
t.Error("Unexpected result for miek.nl", txt, "!= Hello world")
|
||||
}
|
||||
|
||||
m.SetQuestion("example.com.", TypeTXT)
|
||||
r, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Fatal("failed to exchange example.com", err)
|
||||
}
|
||||
txt = r.Extra[0].(*TXT).Txt[0]
|
||||
if txt != "Hello example" {
|
||||
t.Error("Unexpected result for example.com", txt, "!= Hello example")
|
||||
}
|
||||
|
||||
// Test Mixes cased as noticed by Ask.
|
||||
m.SetQuestion("eXaMplE.cOm.", TypeTXT)
|
||||
r, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Error("failed to exchange eXaMplE.cOm", err)
|
||||
}
|
||||
txt = r.Extra[0].(*TXT).Txt[0]
|
||||
if txt != "Hello example" {
|
||||
t.Error("Unexpected result for example.com", txt, "!= Hello example")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkServe(b *testing.B) {
|
||||
b.StopTimer()
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
a := runtime.GOMAXPROCS(4)
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl", TypeSOA)
|
||||
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Exchange(m, addrstr)
|
||||
}
|
||||
runtime.GOMAXPROCS(a)
|
||||
}
|
||||
|
||||
func benchmarkServe6(b *testing.B) {
|
||||
b.StopTimer()
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
a := runtime.GOMAXPROCS(4)
|
||||
s, addrstr, err := RunLocalUDPServer("[::1]:0")
|
||||
if err != nil {
|
||||
b.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl", TypeSOA)
|
||||
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Exchange(m, addrstr)
|
||||
}
|
||||
runtime.GOMAXPROCS(a)
|
||||
}
|
||||
|
||||
func HelloServerCompress(w ResponseWriter, req *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetReply(req)
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
m.Compress = true
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func BenchmarkServeCompress(b *testing.B) {
|
||||
b.StopTimer()
|
||||
HandleFunc("miek.nl.", HelloServerCompress)
|
||||
defer HandleRemove("miek.nl.")
|
||||
a := runtime.GOMAXPROCS(4)
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl", TypeSOA)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Exchange(m, addrstr)
|
||||
}
|
||||
runtime.GOMAXPROCS(a)
|
||||
}
|
||||
|
||||
func TestDotAsCatchAllWildcard(t *testing.T) {
|
||||
mux := NewServeMux()
|
||||
mux.Handle(".", HandlerFunc(HelloServer))
|
||||
mux.Handle("example.com.", HandlerFunc(AnotherHelloServer))
|
||||
|
||||
handler := mux.match("www.miek.nl.", TypeTXT)
|
||||
if handler == nil {
|
||||
t.Error("wildcard match failed")
|
||||
}
|
||||
|
||||
handler = mux.match("www.example.com.", TypeTXT)
|
||||
if handler == nil {
|
||||
t.Error("example.com match failed")
|
||||
}
|
||||
|
||||
handler = mux.match("a.www.example.com.", TypeTXT)
|
||||
if handler == nil {
|
||||
t.Error("a.www.example.com match failed")
|
||||
}
|
||||
|
||||
handler = mux.match("boe.", TypeTXT)
|
||||
if handler == nil {
|
||||
t.Error("boe. match failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaseFolding(t *testing.T) {
|
||||
mux := NewServeMux()
|
||||
mux.Handle("_udp.example.com.", HandlerFunc(HelloServer))
|
||||
|
||||
handler := mux.match("_dns._udp.example.com.", TypeSRV)
|
||||
if handler == nil {
|
||||
t.Error("case sensitive characters folded")
|
||||
}
|
||||
|
||||
handler = mux.match("_DNS._UDP.EXAMPLE.COM.", TypeSRV)
|
||||
if handler == nil {
|
||||
t.Error("case insensitive characters not folded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootServer(t *testing.T) {
|
||||
mux := NewServeMux()
|
||||
mux.Handle(".", HandlerFunc(HelloServer))
|
||||
|
||||
handler := mux.match(".", TypeNS)
|
||||
if handler == nil {
|
||||
t.Error("root match failed")
|
||||
}
|
||||
}
|
||||
|
||||
type maxRec struct {
|
||||
max int
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
var M = new(maxRec)
|
||||
|
||||
func HelloServerLargeResponse(resp ResponseWriter, req *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetReply(req)
|
||||
m.Authoritative = true
|
||||
m1 := 0
|
||||
M.RLock()
|
||||
m1 = M.max
|
||||
M.RUnlock()
|
||||
for i := 0; i < m1; i++ {
|
||||
aRec := &A{
|
||||
Hdr: RR_Header{
|
||||
Name: req.Question[0].Name,
|
||||
Rrtype: TypeA,
|
||||
Class: ClassINET,
|
||||
Ttl: 0,
|
||||
},
|
||||
A: net.ParseIP(fmt.Sprintf("127.0.0.%d", i+1)).To4(),
|
||||
}
|
||||
m.Answer = append(m.Answer, aRec)
|
||||
}
|
||||
resp.WriteMsg(m)
|
||||
}
|
||||
|
||||
func TestServingLargeResponses(t *testing.T) {
|
||||
HandleFunc("example.", HelloServerLargeResponse)
|
||||
defer HandleRemove("example.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
// Create request
|
||||
m := new(Msg)
|
||||
m.SetQuestion("web.service.example.", TypeANY)
|
||||
|
||||
c := new(Client)
|
||||
c.Net = "udp"
|
||||
M.Lock()
|
||||
M.max = 2
|
||||
M.Unlock()
|
||||
_, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
// This must fail
|
||||
M.Lock()
|
||||
M.max = 20
|
||||
M.Unlock()
|
||||
_, _, err = c.Exchange(m, addrstr)
|
||||
if err == nil {
|
||||
t.Error("failed to fail exchange, this should generate packet error")
|
||||
}
|
||||
// But this must work again
|
||||
c.UDPSize = 7000
|
||||
_, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServingResponse(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeTXT)
|
||||
m.Response = false
|
||||
_, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Fatal("failed to exchange", err)
|
||||
}
|
||||
m.Response = true
|
||||
_, _, err = c.Exchange(m, addrstr)
|
||||
if err == nil {
|
||||
t.Fatal("exchanged response message")
|
||||
}
|
||||
|
||||
s.Shutdown()
|
||||
s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m.Response = true
|
||||
_, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Fatal("could exchanged response message in Unsafe mode")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownTCP(t *testing.T) {
|
||||
s, _, err := RunLocalTCPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
err = s.Shutdown()
|
||||
if err != nil {
|
||||
t.Errorf("Could not shutdown test TCP server, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownUDP(t *testing.T) {
|
||||
s, _, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to run test server: %v", err)
|
||||
}
|
||||
err = s.Shutdown()
|
||||
if err != nil {
|
||||
t.Errorf("Could not shutdown test UDP server, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type ExampleFrameLengthWriter struct {
|
||||
Writer
|
||||
}
|
||||
|
||||
func (e *ExampleFrameLengthWriter) Write(m []byte) (int, error) {
|
||||
fmt.Println("writing raw DNS message of length", len(m))
|
||||
return e.Writer.Write(m)
|
||||
}
|
||||
|
||||
func ExampleDecorateWriter() {
|
||||
// instrument raw DNS message writing
|
||||
wf := DecorateWriter(func(w Writer) Writer {
|
||||
return &ExampleFrameLengthWriter{w}
|
||||
})
|
||||
|
||||
// simple UDP server
|
||||
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
server := &Server{
|
||||
PacketConn: pc,
|
||||
DecorateWriter: wf,
|
||||
}
|
||||
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
server.NotifyStartedFunc = waitLock.Unlock
|
||||
defer server.Shutdown()
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
pc.Close()
|
||||
}()
|
||||
|
||||
waitLock.Lock()
|
||||
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
|
||||
c := new(Client)
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeTXT)
|
||||
_, _, err = c.Exchange(m, pc.LocalAddr().String())
|
||||
if err != nil {
|
||||
fmt.Println("failed to exchange", err.Error())
|
||||
return
|
||||
}
|
||||
// Output: writing raw DNS message of length 56
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
// Sign signs a dns.Msg. It fills the signature with the appropriate data.
|
||||
// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
|
||||
// and Expiration set.
|
||||
func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
|
||||
func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
||||
if k == nil {
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
|
|
@ -41,31 +41,26 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
buf = buf[:off:cap(buf)]
|
||||
var hash crypto.Hash
|
||||
switch rr.Algorithm {
|
||||
case DSA, RSASHA1:
|
||||
hash = crypto.SHA1
|
||||
case RSASHA256, ECDSAP256SHA256:
|
||||
hash = crypto.SHA256
|
||||
case ECDSAP384SHA384:
|
||||
hash = crypto.SHA384
|
||||
case RSASHA512:
|
||||
hash = crypto.SHA512
|
||||
default:
|
||||
|
||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||
if !ok {
|
||||
return nil, ErrAlg
|
||||
}
|
||||
|
||||
hasher := hash.New()
|
||||
// Write SIG rdata
|
||||
hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
|
||||
// Write message
|
||||
hasher.Write(buf[:len(mbuf)])
|
||||
hashed := hasher.Sum(nil)
|
||||
|
||||
sig, err := k.Sign(hashed, rr.Algorithm)
|
||||
signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rr.Signature = toBase64(sig)
|
||||
|
||||
rr.Signature = toBase64(signature)
|
||||
sig := string(signature)
|
||||
|
||||
buf = append(buf, sig...)
|
||||
if len(buf) > int(^uint16(0)) {
|
||||
return nil, ErrBuf
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSIG0(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
m := new(Msg)
|
||||
m.SetQuestion("example.org.", TypeSOA)
|
||||
for _, alg := range []uint8{DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} {
|
||||
algstr := AlgorithmToString[alg]
|
||||
keyrr := new(KEY)
|
||||
keyrr.Hdr.Name = algstr + "."
|
||||
keyrr.Hdr.Rrtype = TypeKEY
|
||||
keyrr.Hdr.Class = ClassINET
|
||||
keyrr.Algorithm = alg
|
||||
keysize := 1024
|
||||
switch alg {
|
||||
case ECDSAP256SHA256:
|
||||
keysize = 256
|
||||
case ECDSAP384SHA384:
|
||||
keysize = 384
|
||||
}
|
||||
pk, err := keyrr.Generate(keysize)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to generate key for “%s”: %v", algstr, err)
|
||||
continue
|
||||
}
|
||||
now := uint32(time.Now().Unix())
|
||||
sigrr := new(SIG)
|
||||
sigrr.Hdr.Name = "."
|
||||
sigrr.Hdr.Rrtype = TypeSIG
|
||||
sigrr.Hdr.Class = ClassANY
|
||||
sigrr.Algorithm = alg
|
||||
sigrr.Expiration = now + 300
|
||||
sigrr.Inception = now - 300
|
||||
sigrr.KeyTag = keyrr.KeyTag()
|
||||
sigrr.SignerName = keyrr.Hdr.Name
|
||||
mb, err := sigrr.Sign(pk, m)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to sign message using “%s”: %v", algstr, err)
|
||||
continue
|
||||
}
|
||||
m := new(Msg)
|
||||
if err := m.Unpack(mb); err != nil {
|
||||
t.Errorf("Failed to unpack message signed using “%s”: %v", algstr, err)
|
||||
continue
|
||||
}
|
||||
if len(m.Extra) != 1 {
|
||||
t.Errorf("Missing SIG for message signed using “%s”", algstr)
|
||||
continue
|
||||
}
|
||||
var sigrrwire *SIG
|
||||
switch rr := m.Extra[0].(type) {
|
||||
case *SIG:
|
||||
sigrrwire = rr
|
||||
default:
|
||||
t.Errorf("Expected SIG RR, instead: %v", rr)
|
||||
continue
|
||||
}
|
||||
for _, rr := range []*SIG{sigrr, sigrrwire} {
|
||||
id := "sigrr"
|
||||
if rr == sigrrwire {
|
||||
id = "sigrrwire"
|
||||
}
|
||||
if err := rr.Verify(keyrr, mb); err != nil {
|
||||
t.Errorf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
mb[13]++
|
||||
if err := sigrr.Verify(keyrr, mb); err == nil {
|
||||
t.Errorf("Verify succeeded on an altered message using “%s”", algstr)
|
||||
continue
|
||||
}
|
||||
sigrr.Expiration = 2
|
||||
sigrr.Inception = 1
|
||||
mb, _ = sigrr.Sign(pk, m)
|
||||
if err := sigrr.Verify(keyrr, mb); err == nil {
|
||||
t.Errorf("Verify succeeded on an expired message using “%s”", algstr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,10 +37,6 @@ type TSIG struct {
|
|||
OtherData string `dns:"size-hex"`
|
||||
}
|
||||
|
||||
func (rr *TSIG) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
// TSIG has no official presentation format, but this will suffice.
|
||||
|
||||
func (rr *TSIG) String() string {
|
||||
|
|
@ -58,15 +54,6 @@ func (rr *TSIG) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (rr *TSIG) len() int {
|
||||
return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
|
||||
4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
|
||||
}
|
||||
|
||||
func (rr *TSIG) copy() RR {
|
||||
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
||||
}
|
||||
|
||||
// The following values must be put in wireformat, so that the MAC can be calculated.
|
||||
// RFC 2845, section 3.4.2. TSIG Variables.
|
||||
type tsigWireFmt struct {
|
||||
|
|
|
|||
|
|
@ -91,26 +91,24 @@ const (
|
|||
TypeLP uint16 = 107
|
||||
TypeEUI48 uint16 = 108
|
||||
TypeEUI64 uint16 = 109
|
||||
TypeURI uint16 = 256
|
||||
TypeCAA uint16 = 257
|
||||
|
||||
TypeTKEY uint16 = 249
|
||||
TypeTSIG uint16 = 250
|
||||
|
||||
// valid Question.Qtype only
|
||||
|
||||
TypeIXFR uint16 = 251
|
||||
TypeAXFR uint16 = 252
|
||||
TypeMAILB uint16 = 253
|
||||
TypeMAILA uint16 = 254
|
||||
TypeANY uint16 = 255
|
||||
|
||||
TypeURI uint16 = 256
|
||||
TypeCAA uint16 = 257
|
||||
TypeTA uint16 = 32768
|
||||
TypeDLV uint16 = 32769
|
||||
TypeReserved uint16 = 65535
|
||||
|
||||
// valid Question.Qclass
|
||||
|
||||
ClassINET = 1
|
||||
ClassCSNET = 2
|
||||
ClassCHAOS = 3
|
||||
|
|
@ -118,8 +116,7 @@ const (
|
|||
ClassNONE = 254
|
||||
ClassANY = 255
|
||||
|
||||
// Msg.rcode
|
||||
|
||||
// Message Response Codes.
|
||||
RcodeSuccess = 0
|
||||
RcodeFormatError = 1
|
||||
RcodeServerFailure = 2
|
||||
|
|
@ -140,8 +137,7 @@ const (
|
|||
RcodeBadAlg = 21
|
||||
RcodeBadTrunc = 22 // TSIG
|
||||
|
||||
// Opcode, there is no 3
|
||||
|
||||
// Message Opcodes. There is no 3.
|
||||
OpcodeQuery = 0
|
||||
OpcodeIQuery = 1
|
||||
OpcodeStatus = 2
|
||||
|
|
@ -149,7 +145,7 @@ const (
|
|||
OpcodeUpdate = 5
|
||||
)
|
||||
|
||||
// The wire format for the DNS packet header.
|
||||
// Headers is the wire format for the DNS packet header.
|
||||
type Header struct {
|
||||
Id uint16
|
||||
Bits uint16
|
||||
|
|
@ -178,7 +174,7 @@ const (
|
|||
LOC_ALTITUDEBASE = 100000
|
||||
)
|
||||
|
||||
// RFC 4398, Section 2.1
|
||||
// Different Certificate Types, see RFC 4398, Section 2.1
|
||||
const (
|
||||
CertPKIX = 1 + iota
|
||||
CertSPKI
|
||||
|
|
@ -192,6 +188,8 @@ const (
|
|||
CertOID = 254
|
||||
)
|
||||
|
||||
// CertTypeToString converts the Cert Type to its string representation.
|
||||
// See RFC 4398 and RFC 6944.
|
||||
var CertTypeToString = map[uint16]string{
|
||||
CertPKIX: "PKIX",
|
||||
CertSPKI: "SPKI",
|
||||
|
|
@ -205,8 +203,11 @@ var CertTypeToString = map[uint16]string{
|
|||
CertOID: "OID",
|
||||
}
|
||||
|
||||
// StringToCertType is the reverseof CertTypeToString.
|
||||
var StringToCertType = reverseInt16(CertTypeToString)
|
||||
|
||||
//go:generate go run types_generate.go
|
||||
|
||||
// Question holds a DNS question. There can be multiple questions in the
|
||||
// question section of a message. Usually there is just one.
|
||||
type Question struct {
|
||||
|
|
@ -215,6 +216,10 @@ type Question struct {
|
|||
Qclass uint16
|
||||
}
|
||||
|
||||
func (q *Question) len() int {
|
||||
return len(q.Name) + 1 + 2 + 2
|
||||
}
|
||||
|
||||
func (q *Question) String() (s string) {
|
||||
// prefix with ; (as in dig)
|
||||
s = ";" + sprintName(q.Name) + "\t"
|
||||
|
|
@ -223,30 +228,21 @@ func (q *Question) String() (s string) {
|
|||
return s
|
||||
}
|
||||
|
||||
func (q *Question) len() int {
|
||||
l := len(q.Name) + 1
|
||||
return l + 4
|
||||
}
|
||||
|
||||
// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
|
||||
// is named "*" there.
|
||||
type ANY struct {
|
||||
Hdr RR_Header
|
||||
// Does not have any rdata
|
||||
}
|
||||
|
||||
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *ANY) copy() RR { return &ANY{*rr.Hdr.copyHeader()} }
|
||||
func (rr *ANY) String() string { return rr.Hdr.String() }
|
||||
func (rr *ANY) len() int { return rr.Hdr.len() }
|
||||
func (rr *ANY) String() string { return rr.Hdr.String() }
|
||||
|
||||
type CNAME struct {
|
||||
Hdr RR_Header
|
||||
Target string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CNAME) copy() RR { return &CNAME{*rr.Hdr.copyHeader(), sprintName(rr.Target)} }
|
||||
func (rr *CNAME) String() string { return rr.Hdr.String() + rr.Target }
|
||||
func (rr *CNAME) len() int { return rr.Hdr.len() + len(rr.Target) + 1 }
|
||||
func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
|
||||
|
||||
type HINFO struct {
|
||||
Hdr RR_Header
|
||||
|
|
@ -254,33 +250,23 @@ type HINFO struct {
|
|||
Os string
|
||||
}
|
||||
|
||||
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HINFO) copy() RR { return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} }
|
||||
func (rr *HINFO) String() string {
|
||||
return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
|
||||
}
|
||||
func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) }
|
||||
|
||||
type MB struct {
|
||||
Hdr RR_Header
|
||||
Mb string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MB) copy() RR { return &MB{*rr.Hdr.copyHeader(), sprintName(rr.Mb)} }
|
||||
|
||||
func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb }
|
||||
func (rr *MB) len() int { return rr.Hdr.len() + len(rr.Mb) + 1 }
|
||||
func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) }
|
||||
|
||||
type MG struct {
|
||||
Hdr RR_Header
|
||||
Mg string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MG) copy() RR { return &MG{*rr.Hdr.copyHeader(), rr.Mg} }
|
||||
func (rr *MG) len() int { l := len(rr.Mg) + 1; return rr.Hdr.len() + l }
|
||||
func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
|
||||
func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
|
||||
|
||||
type MINFO struct {
|
||||
Hdr RR_Header
|
||||
|
|
@ -288,28 +274,15 @@ type MINFO struct {
|
|||
Email string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MINFO) copy() RR { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} }
|
||||
|
||||
func (rr *MINFO) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
|
||||
}
|
||||
|
||||
func (rr *MINFO) len() int {
|
||||
l := len(rr.Rmail) + 1
|
||||
n := len(rr.Email) + 1
|
||||
return rr.Hdr.len() + l + n
|
||||
}
|
||||
|
||||
type MR struct {
|
||||
Hdr RR_Header
|
||||
Mr string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MR) copy() RR { return &MR{*rr.Hdr.copyHeader(), rr.Mr} }
|
||||
func (rr *MR) len() int { l := len(rr.Mr) + 1; return rr.Hdr.len() + l }
|
||||
|
||||
func (rr *MR) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Mr)
|
||||
}
|
||||
|
|
@ -319,10 +292,6 @@ type MF struct {
|
|||
Mf string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MF) copy() RR { return &MF{*rr.Hdr.copyHeader(), rr.Mf} }
|
||||
func (rr *MF) len() int { return rr.Hdr.len() + len(rr.Mf) + 1 }
|
||||
|
||||
func (rr *MF) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Mf)
|
||||
}
|
||||
|
|
@ -332,10 +301,6 @@ type MD struct {
|
|||
Md string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MD) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MD) copy() RR { return &MD{*rr.Hdr.copyHeader(), rr.Md} }
|
||||
func (rr *MD) len() int { return rr.Hdr.len() + len(rr.Md) + 1 }
|
||||
|
||||
func (rr *MD) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Md)
|
||||
}
|
||||
|
|
@ -346,10 +311,6 @@ type MX struct {
|
|||
Mx string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *MX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MX) copy() RR { return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} }
|
||||
func (rr *MX) len() int { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 }
|
||||
|
||||
func (rr *MX) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
|
||||
}
|
||||
|
|
@ -360,10 +321,6 @@ type AFSDB struct {
|
|||
Hostname string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AFSDB) copy() RR { return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} }
|
||||
func (rr *AFSDB) len() int { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 }
|
||||
|
||||
func (rr *AFSDB) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
|
||||
}
|
||||
|
|
@ -373,10 +330,6 @@ type X25 struct {
|
|||
PSDNAddress string
|
||||
}
|
||||
|
||||
func (rr *X25) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *X25) copy() RR { return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} }
|
||||
func (rr *X25) len() int { return rr.Hdr.len() + len(rr.PSDNAddress) + 1 }
|
||||
|
||||
func (rr *X25) String() string {
|
||||
return rr.Hdr.String() + rr.PSDNAddress
|
||||
}
|
||||
|
|
@ -387,10 +340,6 @@ type RT struct {
|
|||
Host string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RT) copy() RR { return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} }
|
||||
func (rr *RT) len() int { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 }
|
||||
|
||||
func (rr *RT) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
|
||||
}
|
||||
|
|
@ -400,10 +349,6 @@ type NS struct {
|
|||
Ns string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *NS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NS) len() int { l := len(rr.Ns) + 1; return rr.Hdr.len() + l }
|
||||
func (rr *NS) copy() RR { return &NS{*rr.Hdr.copyHeader(), rr.Ns} }
|
||||
|
||||
func (rr *NS) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Ns)
|
||||
}
|
||||
|
|
@ -413,10 +358,6 @@ type PTR struct {
|
|||
Ptr string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PTR) copy() RR { return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} }
|
||||
func (rr *PTR) len() int { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l }
|
||||
|
||||
func (rr *PTR) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Ptr)
|
||||
}
|
||||
|
|
@ -427,10 +368,6 @@ type RP struct {
|
|||
Txt string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *RP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RP) copy() RR { return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} }
|
||||
func (rr *RP) len() int { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 }
|
||||
|
||||
func (rr *RP) String() string {
|
||||
return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
|
||||
}
|
||||
|
|
@ -446,11 +383,6 @@ type SOA struct {
|
|||
Minttl uint32
|
||||
}
|
||||
|
||||
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SOA) copy() RR {
|
||||
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
||||
}
|
||||
|
||||
func (rr *SOA) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
|
||||
" " + strconv.FormatInt(int64(rr.Serial), 10) +
|
||||
|
|
@ -460,24 +392,11 @@ func (rr *SOA) String() string {
|
|||
" " + strconv.FormatInt(int64(rr.Minttl), 10)
|
||||
}
|
||||
|
||||
func (rr *SOA) len() int {
|
||||
l := len(rr.Ns) + 1
|
||||
n := len(rr.Mbox) + 1
|
||||
return rr.Hdr.len() + l + n + 20
|
||||
}
|
||||
|
||||
type TXT struct {
|
||||
Hdr RR_Header
|
||||
Txt []string `dns:"txt"`
|
||||
}
|
||||
|
||||
func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TXT) copy() RR {
|
||||
cp := make([]string, len(rr.Txt), cap(rr.Txt))
|
||||
copy(cp, rr.Txt)
|
||||
return &TXT{*rr.Hdr.copyHeader(), cp}
|
||||
}
|
||||
|
||||
func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
||||
|
||||
func sprintName(s string) string {
|
||||
|
|
@ -620,36 +539,13 @@ func nextByte(b []byte, offset int) (byte, int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (rr *TXT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, t := range rr.Txt {
|
||||
l += len(t) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
type SPF struct {
|
||||
Hdr RR_Header
|
||||
Txt []string `dns:"txt"`
|
||||
}
|
||||
|
||||
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SPF) copy() RR {
|
||||
cp := make([]string, len(rr.Txt), cap(rr.Txt))
|
||||
copy(cp, rr.Txt)
|
||||
return &SPF{*rr.Hdr.copyHeader(), cp}
|
||||
}
|
||||
|
||||
func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
||||
|
||||
func (rr *SPF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, t := range rr.Txt {
|
||||
l += len(t) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
type SRV struct {
|
||||
Hdr RR_Header
|
||||
Priority uint16
|
||||
|
|
@ -658,12 +554,6 @@ type SRV struct {
|
|||
Target string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SRV) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l + 6 }
|
||||
func (rr *SRV) copy() RR {
|
||||
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
|
||||
}
|
||||
|
||||
func (rr *SRV) String() string {
|
||||
return rr.Hdr.String() +
|
||||
strconv.Itoa(int(rr.Priority)) + " " +
|
||||
|
|
@ -681,11 +571,6 @@ type NAPTR struct {
|
|||
Replacement string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NAPTR) copy() RR {
|
||||
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
|
||||
}
|
||||
|
||||
func (rr *NAPTR) String() string {
|
||||
return rr.Hdr.String() +
|
||||
strconv.Itoa(int(rr.Order)) + " " +
|
||||
|
|
@ -696,12 +581,7 @@ func (rr *NAPTR) String() string {
|
|||
rr.Replacement
|
||||
}
|
||||
|
||||
func (rr *NAPTR) len() int {
|
||||
return rr.Hdr.len() + 4 + len(rr.Flags) + 1 + len(rr.Service) + 1 +
|
||||
len(rr.Regexp) + 1 + len(rr.Replacement) + 1
|
||||
}
|
||||
|
||||
// See RFC 4398.
|
||||
// The CERT resource record, see RFC 4398.
|
||||
type CERT struct {
|
||||
Hdr RR_Header
|
||||
Type uint16
|
||||
|
|
@ -710,11 +590,6 @@ type CERT struct {
|
|||
Certificate string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CERT) copy() RR {
|
||||
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
|
||||
}
|
||||
|
||||
func (rr *CERT) String() string {
|
||||
var (
|
||||
ok bool
|
||||
|
|
@ -732,21 +607,12 @@ func (rr *CERT) String() string {
|
|||
" " + rr.Certificate
|
||||
}
|
||||
|
||||
func (rr *CERT) len() int {
|
||||
return rr.Hdr.len() + 5 +
|
||||
base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
||||
}
|
||||
|
||||
// See RFC 2672.
|
||||
// The DNAME resource record, see RFC 2672.
|
||||
type DNAME struct {
|
||||
Hdr RR_Header
|
||||
Target string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNAME) copy() RR { return &DNAME{*rr.Hdr.copyHeader(), rr.Target} }
|
||||
func (rr *DNAME) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l }
|
||||
|
||||
func (rr *DNAME) String() string {
|
||||
return rr.Hdr.String() + sprintName(rr.Target)
|
||||
}
|
||||
|
|
@ -756,10 +622,6 @@ type A struct {
|
|||
A net.IP `dns:"a"`
|
||||
}
|
||||
|
||||
func (rr *A) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *A) copy() RR { return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} }
|
||||
func (rr *A) len() int { return rr.Hdr.len() + net.IPv4len }
|
||||
|
||||
func (rr *A) String() string {
|
||||
if rr.A == nil {
|
||||
return rr.Hdr.String()
|
||||
|
|
@ -772,10 +634,6 @@ type AAAA struct {
|
|||
AAAA net.IP `dns:"aaaa"`
|
||||
}
|
||||
|
||||
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AAAA) copy() RR { return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} }
|
||||
func (rr *AAAA) len() int { return rr.Hdr.len() + net.IPv6len }
|
||||
|
||||
func (rr *AAAA) String() string {
|
||||
if rr.AAAA == nil {
|
||||
return rr.Hdr.String()
|
||||
|
|
@ -790,12 +648,9 @@ type PX struct {
|
|||
Mapx400 string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PX) copy() RR { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} }
|
||||
func (rr *PX) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
|
||||
}
|
||||
func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 }
|
||||
|
||||
type GPOS struct {
|
||||
Hdr RR_Header
|
||||
|
|
@ -804,11 +659,6 @@ type GPOS struct {
|
|||
Altitude string
|
||||
}
|
||||
|
||||
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *GPOS) copy() RR { return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} }
|
||||
func (rr *GPOS) len() int {
|
||||
return rr.Hdr.len() + len(rr.Longitude) + len(rr.Latitude) + len(rr.Altitude) + 3
|
||||
}
|
||||
func (rr *GPOS) String() string {
|
||||
return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
|
||||
}
|
||||
|
|
@ -824,12 +674,6 @@ type LOC struct {
|
|||
Altitude uint32
|
||||
}
|
||||
|
||||
func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *LOC) len() int { return rr.Hdr.len() + 4 + 12 }
|
||||
func (rr *LOC) copy() RR {
|
||||
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
|
||||
}
|
||||
|
||||
// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent
|
||||
// format and returns a string in m (two decimals for the cm)
|
||||
func cmToM(m, e uint8) string {
|
||||
|
|
@ -913,11 +757,6 @@ type RRSIG struct {
|
|||
Signature string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RRSIG) copy() RR {
|
||||
return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
|
||||
}
|
||||
|
||||
func (rr *RRSIG) String() string {
|
||||
s := rr.Hdr.String()
|
||||
s += Type(rr.TypeCovered).String()
|
||||
|
|
@ -932,24 +771,12 @@ func (rr *RRSIG) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (rr *RRSIG) len() int {
|
||||
return rr.Hdr.len() + len(rr.SignerName) + 1 +
|
||||
base64.StdEncoding.DecodedLen(len(rr.Signature)) + 18
|
||||
}
|
||||
|
||||
type NSEC struct {
|
||||
Hdr RR_Header
|
||||
NextDomain string `dns:"domain-name"`
|
||||
TypeBitMap []uint16 `dns:"nsec"`
|
||||
}
|
||||
|
||||
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC) copy() RR {
|
||||
cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap))
|
||||
copy(cp, rr.TypeBitMap)
|
||||
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, cp}
|
||||
}
|
||||
|
||||
func (rr *NSEC) String() string {
|
||||
s := rr.Hdr.String() + sprintName(rr.NextDomain)
|
||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||
|
|
@ -987,12 +814,6 @@ type DS struct {
|
|||
Digest string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *DS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DS) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 }
|
||||
func (rr *DS) copy() RR {
|
||||
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
|
||||
func (rr *DS) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
|
||||
" " + strconv.Itoa(int(rr.Algorithm)) +
|
||||
|
|
@ -1006,10 +827,6 @@ type KX struct {
|
|||
Exchanger string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *KX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KX) len() int { return rr.Hdr.len() + 2 + len(rr.Exchanger) + 1 }
|
||||
func (rr *KX) copy() RR { return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} }
|
||||
|
||||
func (rr *KX) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
|
||||
" " + sprintName(rr.Exchanger)
|
||||
|
|
@ -1023,12 +840,6 @@ type TA struct {
|
|||
Digest string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *TA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TA) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 }
|
||||
func (rr *TA) copy() RR {
|
||||
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
|
||||
func (rr *TA) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
|
||||
" " + strconv.Itoa(int(rr.Algorithm)) +
|
||||
|
|
@ -1042,10 +853,6 @@ type TALINK struct {
|
|||
NextName string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TALINK) copy() RR { return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} }
|
||||
func (rr *TALINK) len() int { return rr.Hdr.len() + len(rr.PreviousName) + len(rr.NextName) + 2 }
|
||||
|
||||
func (rr *TALINK) String() string {
|
||||
return rr.Hdr.String() +
|
||||
sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
|
||||
|
|
@ -1058,12 +865,6 @@ type SSHFP struct {
|
|||
FingerPrint string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SSHFP) len() int { return rr.Hdr.len() + 2 + len(rr.FingerPrint)/2 }
|
||||
func (rr *SSHFP) copy() RR {
|
||||
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
|
||||
}
|
||||
|
||||
func (rr *SSHFP) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
|
||||
" " + strconv.Itoa(int(rr.Type)) +
|
||||
|
|
@ -1084,11 +885,6 @@ type IPSECKEY struct {
|
|||
PublicKey string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *IPSECKEY) copy() RR {
|
||||
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.GatewayA, rr.GatewayAAAA, rr.GatewayName, rr.PublicKey}
|
||||
}
|
||||
|
||||
func (rr *IPSECKEY) String() string {
|
||||
s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
|
||||
" " + strconv.Itoa(int(rr.GatewayType)) +
|
||||
|
|
@ -1142,14 +938,6 @@ type DNSKEY struct {
|
|||
PublicKey string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNSKEY) len() int {
|
||||
return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
}
|
||||
func (rr *DNSKEY) copy() RR {
|
||||
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
|
||||
func (rr *DNSKEY) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
|
||||
" " + strconv.Itoa(int(rr.Protocol)) +
|
||||
|
|
@ -1165,12 +953,6 @@ type RKEY struct {
|
|||
PublicKey string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RKEY) len() int { return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) }
|
||||
func (rr *RKEY) copy() RR {
|
||||
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
|
||||
func (rr *RKEY) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
|
||||
" " + strconv.Itoa(int(rr.Protocol)) +
|
||||
|
|
@ -1183,10 +965,7 @@ type NSAPPTR struct {
|
|||
Ptr string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSAPPTR) copy() RR { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} }
|
||||
func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
|
||||
func (rr *NSAPPTR) len() int { return rr.Hdr.len() + len(rr.Ptr) }
|
||||
func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
|
||||
|
||||
type NSEC3 struct {
|
||||
Hdr RR_Header
|
||||
|
|
@ -1200,13 +979,6 @@ type NSEC3 struct {
|
|||
TypeBitMap []uint16 `dns:"nsec"`
|
||||
}
|
||||
|
||||
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3) copy() RR {
|
||||
cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap))
|
||||
copy(cp, rr.TypeBitMap)
|
||||
return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, cp}
|
||||
}
|
||||
|
||||
func (rr *NSEC3) String() string {
|
||||
s := rr.Hdr.String()
|
||||
s += strconv.Itoa(int(rr.Hash)) +
|
||||
|
|
@ -1242,12 +1014,6 @@ type NSEC3PARAM struct {
|
|||
Salt string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3PARAM) len() int { return rr.Hdr.len() + 2 + 4 + 1 + len(rr.Salt)/2 }
|
||||
func (rr *NSEC3PARAM) copy() RR {
|
||||
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
||||
}
|
||||
|
||||
func (rr *NSEC3PARAM) String() string {
|
||||
s := rr.Hdr.String()
|
||||
s += strconv.Itoa(int(rr.Hash)) +
|
||||
|
|
@ -1270,31 +1036,17 @@ type TKEY struct {
|
|||
OtherData string
|
||||
}
|
||||
|
||||
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TKEY) copy() RR {
|
||||
return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
|
||||
}
|
||||
|
||||
func (rr *TKEY) String() string {
|
||||
// It has no presentation format
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rr *TKEY) len() int {
|
||||
return rr.Hdr.len() + len(rr.Algorithm) + 1 + 4 + 4 + 6 +
|
||||
len(rr.Key) + 2 + len(rr.OtherData)
|
||||
}
|
||||
|
||||
// RFC3597 represents an unknown/generic RR.
|
||||
type RFC3597 struct {
|
||||
Hdr RR_Header
|
||||
Rdata string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RFC3597) copy() RR { return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} }
|
||||
func (rr *RFC3597) len() int { return rr.Hdr.len() + len(rr.Rdata)/2 + 2 }
|
||||
|
||||
func (rr *RFC3597) String() string {
|
||||
// Let's call it a hack
|
||||
s := rfc3597Header(rr.Hdr)
|
||||
|
|
@ -1320,9 +1072,6 @@ type URI struct {
|
|||
Target string `dns:"octet"`
|
||||
}
|
||||
|
||||
func (rr *URI) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *URI) copy() RR { return &URI{*rr.Hdr.copyHeader(), rr.Weight, rr.Priority, rr.Target} }
|
||||
func (rr *URI) len() int { return rr.Hdr.len() + 4 + len(rr.Target) }
|
||||
func (rr *URI) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
|
||||
" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
|
||||
|
|
@ -1333,10 +1082,7 @@ type DHCID struct {
|
|||
Digest string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DHCID) copy() RR { return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} }
|
||||
func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
|
||||
func (rr *DHCID) len() int { return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.Digest)) }
|
||||
func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
|
||||
|
||||
type TLSA struct {
|
||||
Hdr RR_Header
|
||||
|
|
@ -1346,13 +1092,6 @@ type TLSA struct {
|
|||
Certificate string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TLSA) len() int { return rr.Hdr.len() + 3 + len(rr.Certificate)/2 }
|
||||
|
||||
func (rr *TLSA) copy() RR {
|
||||
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
||||
}
|
||||
|
||||
func (rr *TLSA) String() string {
|
||||
return rr.Hdr.String() +
|
||||
strconv.Itoa(int(rr.Usage)) +
|
||||
|
|
@ -1371,13 +1110,6 @@ type HIP struct {
|
|||
RendezvousServers []string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HIP) copy() RR {
|
||||
cp := make([]string, len(rr.RendezvousServers), cap(rr.RendezvousServers))
|
||||
copy(cp, rr.RendezvousServers)
|
||||
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, cp}
|
||||
}
|
||||
|
||||
func (rr *HIP) String() string {
|
||||
s := rr.Hdr.String() +
|
||||
strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
|
||||
|
|
@ -1389,38 +1121,13 @@ func (rr *HIP) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (rr *HIP) len() int {
|
||||
l := rr.Hdr.len() + 4 +
|
||||
len(rr.Hit)/2 +
|
||||
base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
for _, d := range rr.RendezvousServers {
|
||||
l += len(d) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
type NINFO struct {
|
||||
Hdr RR_Header
|
||||
ZSData []string `dns:"txt"`
|
||||
}
|
||||
|
||||
func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NINFO) copy() RR {
|
||||
cp := make([]string, len(rr.ZSData), cap(rr.ZSData))
|
||||
copy(cp, rr.ZSData)
|
||||
return &NINFO{*rr.Hdr.copyHeader(), cp}
|
||||
}
|
||||
|
||||
func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
|
||||
|
||||
func (rr *NINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, t := range rr.ZSData {
|
||||
l += len(t) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
type WKS struct {
|
||||
Hdr RR_Header
|
||||
Address net.IP `dns:"a"`
|
||||
|
|
@ -1428,13 +1135,9 @@ type WKS struct {
|
|||
BitMap []uint16 `dns:"wks"`
|
||||
}
|
||||
|
||||
func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *WKS) len() int { return rr.Hdr.len() + net.IPv4len + 1 }
|
||||
|
||||
func (rr *WKS) copy() RR {
|
||||
cp := make([]uint16, len(rr.BitMap), cap(rr.BitMap))
|
||||
copy(cp, rr.BitMap)
|
||||
return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, cp}
|
||||
func (rr *WKS) len() int {
|
||||
// TODO: this is missing something...
|
||||
return rr.Hdr.len() + net.IPv4len + 1
|
||||
}
|
||||
|
||||
func (rr *WKS) String() (s string) {
|
||||
|
|
@ -1456,10 +1159,6 @@ type NID struct {
|
|||
NodeID uint64
|
||||
}
|
||||
|
||||
func (rr *NID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NID) copy() RR { return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} }
|
||||
func (rr *NID) len() int { return rr.Hdr.len() + 2 + 8 }
|
||||
|
||||
func (rr *NID) String() string {
|
||||
s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
|
||||
node := fmt.Sprintf("%0.16x", rr.NodeID)
|
||||
|
|
@ -1473,10 +1172,6 @@ type L32 struct {
|
|||
Locator32 net.IP `dns:"a"`
|
||||
}
|
||||
|
||||
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L32) copy() RR { return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} }
|
||||
func (rr *L32) len() int { return rr.Hdr.len() + net.IPv4len }
|
||||
|
||||
func (rr *L32) String() string {
|
||||
if rr.Locator32 == nil {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
|
||||
|
|
@ -1491,10 +1186,6 @@ type L64 struct {
|
|||
Locator64 uint64
|
||||
}
|
||||
|
||||
func (rr *L64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L64) copy() RR { return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} }
|
||||
func (rr *L64) len() int { return rr.Hdr.len() + 2 + 8 }
|
||||
|
||||
func (rr *L64) String() string {
|
||||
s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
|
||||
node := fmt.Sprintf("%0.16X", rr.Locator64)
|
||||
|
|
@ -1508,10 +1199,6 @@ type LP struct {
|
|||
Fqdn string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *LP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *LP) copy() RR { return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} }
|
||||
func (rr *LP) len() int { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 }
|
||||
|
||||
func (rr *LP) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
|
||||
}
|
||||
|
|
@ -1521,20 +1208,14 @@ type EUI48 struct {
|
|||
Address uint64 `dns:"uint48"`
|
||||
}
|
||||
|
||||
func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI48) copy() RR { return &EUI48{*rr.Hdr.copyHeader(), rr.Address} }
|
||||
func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
|
||||
func (rr *EUI48) len() int { return rr.Hdr.len() + 6 }
|
||||
func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
|
||||
|
||||
type EUI64 struct {
|
||||
Hdr RR_Header
|
||||
Address uint64
|
||||
}
|
||||
|
||||
func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI64) copy() RR { return &EUI64{*rr.Hdr.copyHeader(), rr.Address} }
|
||||
func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
|
||||
func (rr *EUI64) len() int { return rr.Hdr.len() + 8 }
|
||||
func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
|
||||
|
||||
type CAA struct {
|
||||
Hdr RR_Header
|
||||
|
|
@ -1543,9 +1224,6 @@ type CAA struct {
|
|||
Value string `dns:"octet"`
|
||||
}
|
||||
|
||||
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} }
|
||||
func (rr *CAA) len() int { return rr.Hdr.len() + 2 + len(rr.Tag) + len(rr.Value) }
|
||||
func (rr *CAA) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
|
||||
}
|
||||
|
|
@ -1555,62 +1233,42 @@ type UID struct {
|
|||
Uid uint32
|
||||
}
|
||||
|
||||
func (rr *UID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *UID) copy() RR { return &UID{*rr.Hdr.copyHeader(), rr.Uid} }
|
||||
func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
|
||||
func (rr *UID) len() int { return rr.Hdr.len() + 4 }
|
||||
func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
|
||||
|
||||
type GID struct {
|
||||
Hdr RR_Header
|
||||
Gid uint32
|
||||
}
|
||||
|
||||
func (rr *GID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *GID) copy() RR { return &GID{*rr.Hdr.copyHeader(), rr.Gid} }
|
||||
func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
|
||||
func (rr *GID) len() int { return rr.Hdr.len() + 4 }
|
||||
func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
|
||||
|
||||
type UINFO struct {
|
||||
Hdr RR_Header
|
||||
Uinfo string
|
||||
}
|
||||
|
||||
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *UINFO) copy() RR { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} }
|
||||
func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
|
||||
func (rr *UINFO) len() int { return rr.Hdr.len() + len(rr.Uinfo) + 1 }
|
||||
func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
|
||||
|
||||
type EID struct {
|
||||
Hdr RR_Header
|
||||
Endpoint string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *EID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EID) copy() RR { return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} }
|
||||
func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
|
||||
func (rr *EID) len() int { return rr.Hdr.len() + len(rr.Endpoint)/2 }
|
||||
func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
|
||||
|
||||
type NIMLOC struct {
|
||||
Hdr RR_Header
|
||||
Locator string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NIMLOC) copy() RR { return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} }
|
||||
func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
|
||||
func (rr *NIMLOC) len() int { return rr.Hdr.len() + len(rr.Locator)/2 }
|
||||
func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
|
||||
|
||||
type OPENPGPKEY struct {
|
||||
Hdr RR_Header
|
||||
PublicKey string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPENPGPKEY) copy() RR { return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} }
|
||||
func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
|
||||
func (rr *OPENPGPKEY) len() int {
|
||||
return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
}
|
||||
func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
|
||||
|
||||
// TimeToString translates the RRSIG's incep. and expir. times to the
|
||||
// string representation used when printing the record.
|
||||
|
|
@ -1668,73 +1326,3 @@ func copyIP(ip net.IP) net.IP {
|
|||
copy(p, ip)
|
||||
return p
|
||||
}
|
||||
|
||||
// Map of constructors for each RR type.
|
||||
var typeToRR = map[uint16]func() RR{
|
||||
TypeA: func() RR { return new(A) },
|
||||
TypeAAAA: func() RR { return new(AAAA) },
|
||||
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||
TypeCAA: func() RR { return new(CAA) },
|
||||
TypeCDS: func() RR { return new(CDS) },
|
||||
TypeCERT: func() RR { return new(CERT) },
|
||||
TypeCNAME: func() RR { return new(CNAME) },
|
||||
TypeDHCID: func() RR { return new(DHCID) },
|
||||
TypeDLV: func() RR { return new(DLV) },
|
||||
TypeDNAME: func() RR { return new(DNAME) },
|
||||
TypeKEY: func() RR { return new(KEY) },
|
||||
TypeDNSKEY: func() RR { return new(DNSKEY) },
|
||||
TypeDS: func() RR { return new(DS) },
|
||||
TypeEUI48: func() RR { return new(EUI48) },
|
||||
TypeEUI64: func() RR { return new(EUI64) },
|
||||
TypeGID: func() RR { return new(GID) },
|
||||
TypeGPOS: func() RR { return new(GPOS) },
|
||||
TypeEID: func() RR { return new(EID) },
|
||||
TypeHINFO: func() RR { return new(HINFO) },
|
||||
TypeHIP: func() RR { return new(HIP) },
|
||||
TypeIPSECKEY: func() RR { return new(IPSECKEY) },
|
||||
TypeKX: func() RR { return new(KX) },
|
||||
TypeL32: func() RR { return new(L32) },
|
||||
TypeL64: func() RR { return new(L64) },
|
||||
TypeLOC: func() RR { return new(LOC) },
|
||||
TypeLP: func() RR { return new(LP) },
|
||||
TypeMB: func() RR { return new(MB) },
|
||||
TypeMD: func() RR { return new(MD) },
|
||||
TypeMF: func() RR { return new(MF) },
|
||||
TypeMG: func() RR { return new(MG) },
|
||||
TypeMINFO: func() RR { return new(MINFO) },
|
||||
TypeMR: func() RR { return new(MR) },
|
||||
TypeMX: func() RR { return new(MX) },
|
||||
TypeNAPTR: func() RR { return new(NAPTR) },
|
||||
TypeNID: func() RR { return new(NID) },
|
||||
TypeNINFO: func() RR { return new(NINFO) },
|
||||
TypeNIMLOC: func() RR { return new(NIMLOC) },
|
||||
TypeNS: func() RR { return new(NS) },
|
||||
TypeNSAPPTR: func() RR { return new(NSAPPTR) },
|
||||
TypeNSEC3: func() RR { return new(NSEC3) },
|
||||
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
|
||||
TypeNSEC: func() RR { return new(NSEC) },
|
||||
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
|
||||
TypeOPT: func() RR { return new(OPT) },
|
||||
TypePTR: func() RR { return new(PTR) },
|
||||
TypeRKEY: func() RR { return new(RKEY) },
|
||||
TypeRP: func() RR { return new(RP) },
|
||||
TypePX: func() RR { return new(PX) },
|
||||
TypeSIG: func() RR { return new(SIG) },
|
||||
TypeRRSIG: func() RR { return new(RRSIG) },
|
||||
TypeRT: func() RR { return new(RT) },
|
||||
TypeSOA: func() RR { return new(SOA) },
|
||||
TypeSPF: func() RR { return new(SPF) },
|
||||
TypeSRV: func() RR { return new(SRV) },
|
||||
TypeSSHFP: func() RR { return new(SSHFP) },
|
||||
TypeTA: func() RR { return new(TA) },
|
||||
TypeTALINK: func() RR { return new(TALINK) },
|
||||
TypeTKEY: func() RR { return new(TKEY) },
|
||||
TypeTLSA: func() RR { return new(TLSA) },
|
||||
TypeTSIG: func() RR { return new(TSIG) },
|
||||
TypeTXT: func() RR { return new(TXT) },
|
||||
TypeUID: func() RR { return new(UID) },
|
||||
TypeUINFO: func() RR { return new(UINFO) },
|
||||
TypeURI: func() RR { return new(URI) },
|
||||
TypeWKS: func() RR { return new(WKS) },
|
||||
TypeX25: func() RR { return new(X25) },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,266 @@
|
|||
//+build ignore
|
||||
|
||||
// types_generate.go is meant to run with go generate. It will use
|
||||
// go/{importer,types} to track down all the RR struct types. Then for each type
|
||||
// it will generate conversion tables (TypeToRR and TypeToString) and banal
|
||||
// methods (len, Header, copy) based on the struct tags. The generated source is
|
||||
// written to ztypes.go, and is meant to be checked into git.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"go/importer"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var skipLen = map[string]struct{}{
|
||||
"NSEC": struct{}{},
|
||||
"NSEC3": struct{}{},
|
||||
"OPT": struct{}{},
|
||||
"WKS": struct{}{},
|
||||
"IPSECKEY": struct{}{},
|
||||
}
|
||||
|
||||
var packageHdr = `
|
||||
// *** DO NOT MODIFY ***
|
||||
// AUTOGENERATED BY go generate
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net"
|
||||
)
|
||||
|
||||
`
|
||||
|
||||
var TypeToRR = template.Must(template.New("TypeToRR").Parse(`
|
||||
// TypeToRR is a map of constructors for each RR type.
|
||||
var TypeToRR = map[uint16]func() RR{
|
||||
{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) },
|
||||
{{end}}{{end}} }
|
||||
|
||||
`))
|
||||
|
||||
var typeToString = template.Must(template.New("typeToString").Parse(`
|
||||
// TypeToString is a map of strings for each RR type.
|
||||
var TypeToString = map[uint16]string{
|
||||
{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}",
|
||||
{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR",
|
||||
}
|
||||
|
||||
`))
|
||||
|
||||
var headerFunc = template.Must(template.New("headerFunc").Parse(`
|
||||
// Header() functions
|
||||
{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
|
||||
{{end}}
|
||||
|
||||
`))
|
||||
|
||||
// getTypeStruct will take a type and the package scope, and return the
|
||||
// (innermost) struct if the type is considered a RR type (currently defined as
|
||||
// those structs beginning with a RR_Header, could be redefined as implementing
|
||||
// the RR interface). The bool return value indicates if embedded structs were
|
||||
// resolved.
|
||||
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
|
||||
st, ok := t.Underlying().(*types.Struct)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
|
||||
return st, false
|
||||
}
|
||||
if st.Field(0).Anonymous() {
|
||||
st, _ := getTypeStruct(st.Field(0).Type(), scope)
|
||||
return st, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Import and type-check the package
|
||||
pkg, err := importer.Default().Import("github.com/miekg/dns")
|
||||
fatalIfErr(err)
|
||||
scope := pkg.Scope()
|
||||
|
||||
// Collect constants like TypeX
|
||||
var numberedTypes []string
|
||||
for _, name := range scope.Names() {
|
||||
o := scope.Lookup(name)
|
||||
if o == nil || !o.Exported() {
|
||||
continue
|
||||
}
|
||||
b, ok := o.Type().(*types.Basic)
|
||||
if !ok || b.Kind() != types.Uint16 {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(o.Name(), "Type") {
|
||||
continue
|
||||
}
|
||||
name := strings.TrimPrefix(o.Name(), "Type")
|
||||
if name == "PrivateRR" {
|
||||
continue
|
||||
}
|
||||
numberedTypes = append(numberedTypes, name)
|
||||
}
|
||||
|
||||
// Collect actual types (*X)
|
||||
var namedTypes []string
|
||||
for _, name := range scope.Names() {
|
||||
o := scope.Lookup(name)
|
||||
if o == nil || !o.Exported() {
|
||||
continue
|
||||
}
|
||||
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
|
||||
continue
|
||||
}
|
||||
if name == "PrivateRR" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if corresponding TypeX exists
|
||||
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
|
||||
log.Fatalf("Constant Type%s does not exist.", o.Name())
|
||||
}
|
||||
|
||||
namedTypes = append(namedTypes, o.Name())
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
b.WriteString(packageHdr)
|
||||
|
||||
// Generate TypeToRR
|
||||
fatalIfErr(TypeToRR.Execute(b, namedTypes))
|
||||
|
||||
// Generate typeToString
|
||||
fatalIfErr(typeToString.Execute(b, numberedTypes))
|
||||
|
||||
// Generate headerFunc
|
||||
fatalIfErr(headerFunc.Execute(b, namedTypes))
|
||||
|
||||
// Generate len()
|
||||
fmt.Fprint(b, "// len() functions\n")
|
||||
for _, name := range namedTypes {
|
||||
if _, ok := skipLen[name]; ok {
|
||||
continue
|
||||
}
|
||||
o := scope.Lookup(name)
|
||||
st, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
|
||||
fmt.Fprintf(b, "l := rr.Hdr.len()\n")
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
|
||||
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
switch st.Tag(i) {
|
||||
case `dns:"-"`:
|
||||
// ignored
|
||||
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
|
||||
o("for _, x := range rr.%s { l += len(x) + 1 }\n")
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch st.Tag(i) {
|
||||
case `dns:"-"`:
|
||||
// ignored
|
||||
case `dns:"cdomain-name"`, `dns:"domain-name"`:
|
||||
o("l += len(rr.%s) + 1\n")
|
||||
case `dns:"octet"`:
|
||||
o("l += len(rr.%s)\n")
|
||||
case `dns:"base64"`:
|
||||
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
|
||||
case `dns:"size-hex"`, `dns:"hex"`:
|
||||
o("l += len(rr.%s)/2 + 1\n")
|
||||
case `dns:"a"`:
|
||||
o("l += net.IPv4len // %s\n")
|
||||
case `dns:"aaaa"`:
|
||||
o("l += net.IPv6len // %s\n")
|
||||
case `dns:"txt"`:
|
||||
o("for _, t := range rr.%s { l += len(t) + 1 }\n")
|
||||
case `dns:"uint48"`:
|
||||
o("l += 6 // %s\n")
|
||||
case "":
|
||||
switch st.Field(i).Type().(*types.Basic).Kind() {
|
||||
case types.Uint8:
|
||||
o("l += 1 // %s\n")
|
||||
case types.Uint16:
|
||||
o("l += 2 // %s\n")
|
||||
case types.Uint32:
|
||||
o("l += 4 // %s\n")
|
||||
case types.Uint64:
|
||||
o("l += 8 // %s\n")
|
||||
case types.String:
|
||||
o("l += len(rr.%s) + 1\n")
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name())
|
||||
}
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "return l }\n")
|
||||
}
|
||||
|
||||
// Generate copy()
|
||||
fmt.Fprint(b, "// copy() functions\n")
|
||||
for _, name := range namedTypes {
|
||||
o := scope.Lookup(name)
|
||||
st, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
|
||||
fields := []string{"*rr.Hdr.copyHeader()"}
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
f := st.Field(i).Name()
|
||||
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
t := sl.Underlying().String()
|
||||
t = strings.TrimPrefix(t, "[]")
|
||||
t = strings.TrimPrefix(t, "github.com/miekg/dns.")
|
||||
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
|
||||
f, t, f, f, f)
|
||||
fields = append(fields, f)
|
||||
continue
|
||||
}
|
||||
if st.Field(i).Type().String() == "net.IP" {
|
||||
fields = append(fields, "copyIP(rr."+f+")")
|
||||
continue
|
||||
}
|
||||
fields = append(fields, "rr."+f)
|
||||
}
|
||||
fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ","))
|
||||
fmt.Fprintf(b, "}\n")
|
||||
}
|
||||
|
||||
// gofmt
|
||||
res, err := format.Source(b.Bytes())
|
||||
if err != nil {
|
||||
b.WriteTo(os.Stderr)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// write result
|
||||
f, err := os.Create("ztypes.go")
|
||||
fatalIfErr(err)
|
||||
defer f.Close()
|
||||
f.Write(res)
|
||||
}
|
||||
|
||||
func fatalIfErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCmToM(t *testing.T) {
|
||||
s := cmToM(0, 0)
|
||||
if s != "0.00" {
|
||||
t.Error("0, 0")
|
||||
}
|
||||
|
||||
s = cmToM(1, 0)
|
||||
if s != "0.01" {
|
||||
t.Error("1, 0")
|
||||
}
|
||||
|
||||
s = cmToM(3, 1)
|
||||
if s != "0.30" {
|
||||
t.Error("3, 1")
|
||||
}
|
||||
|
||||
s = cmToM(4, 2)
|
||||
if s != "4" {
|
||||
t.Error("4, 2")
|
||||
}
|
||||
|
||||
s = cmToM(5, 3)
|
||||
if s != "50" {
|
||||
t.Error("5, 3")
|
||||
}
|
||||
|
||||
s = cmToM(7, 5)
|
||||
if s != "7000" {
|
||||
t.Error("7, 5")
|
||||
}
|
||||
|
||||
s = cmToM(9, 9)
|
||||
if s != "90000000" {
|
||||
t.Error("9, 9")
|
||||
}
|
||||
}
|
||||
|
|
@ -7,11 +7,14 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// SessionUDP holds the remote address and the associated
|
||||
// out-of-band data.
|
||||
type SessionUDP struct {
|
||||
raddr *net.UDPAddr
|
||||
context []byte
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||
|
||||
// setUDPSocketOptions sets the UDP socket options.
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDynamicUpdateParsing(t *testing.T) {
|
||||
prefix := "example.com. IN "
|
||||
for _, typ := range TypeToString {
|
||||
if typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
|
||||
typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" {
|
||||
continue
|
||||
}
|
||||
r, err := NewRR(prefix + typ)
|
||||
if err != nil {
|
||||
t.Errorf("failure to parse: %s %s: %v", prefix, typ, err)
|
||||
} else {
|
||||
t.Logf("parsed: %s", r.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicUpdateUnpack(t *testing.T) {
|
||||
// From https://github.com/miekg/dns/issues/150#issuecomment-62296803
|
||||
// It should be an update message for the zone "example.",
|
||||
// deleting the A RRset "example." and then adding an A record at "example.".
|
||||
// class ANY, TYPE A
|
||||
buf := []byte{171, 68, 40, 0, 0, 1, 0, 0, 0, 2, 0, 0, 7, 101, 120, 97, 109, 112, 108, 101, 0, 0, 6, 0, 1, 192, 12, 0, 1, 0, 255, 0, 0, 0, 0, 0, 0, 192, 12, 0, 1, 0, 1, 0, 0, 0, 0, 0, 4, 127, 0, 0, 1}
|
||||
msg := new(Msg)
|
||||
err := msg.Unpack(buf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to unpack: %v\n%s", err, msg.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicUpdateZeroRdataUnpack(t *testing.T) {
|
||||
m := new(Msg)
|
||||
rr := &RR_Header{Name: ".", Rrtype: 0, Class: 1, Ttl: ^uint32(0), Rdlength: 0}
|
||||
m.Answer = []RR{rr, rr, rr, rr, rr}
|
||||
m.Ns = m.Answer
|
||||
for n, s := range TypeToString {
|
||||
rr.Rrtype = n
|
||||
bytes, err := m.Pack()
|
||||
if err != nil {
|
||||
t.Errorf("failed to pack %s: %v", s, err)
|
||||
continue
|
||||
}
|
||||
if err := new(Msg).Unpack(bytes); err != nil {
|
||||
t.Errorf("failed to unpack %s: %v", s, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveRRset(t *testing.T) {
|
||||
// Should add a zero data RR in Class ANY with a TTL of 0
|
||||
// for each set mentioned in the RRs provided to it.
|
||||
rr, err := NewRR(". 100 IN A 127.0.0.1")
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing RR: %v", err)
|
||||
}
|
||||
m := new(Msg)
|
||||
m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
|
||||
expectstr := m.String()
|
||||
expect, err := m.Pack()
|
||||
if err != nil {
|
||||
t.Fatalf("Error packing expected msg: %v", err)
|
||||
}
|
||||
|
||||
m.Ns = nil
|
||||
m.RemoveRRset([]RR{rr})
|
||||
actual, err := m.Pack()
|
||||
if err != nil {
|
||||
t.Fatalf("Error packing actual msg: %v", err)
|
||||
}
|
||||
if !bytes.Equal(actual, expect) {
|
||||
tmp := new(Msg)
|
||||
if err := tmp.Unpack(actual); err != nil {
|
||||
t.Fatalf("Error unpacking actual msg: %v", err)
|
||||
}
|
||||
t.Errorf("Expected msg:\n%s", expectstr)
|
||||
t.Errorf("Actual msg:\n%v", tmp)
|
||||
}
|
||||
}
|
||||
|
|
@ -23,14 +23,26 @@ type Transfer struct {
|
|||
// Think we need to away to stop the transfer
|
||||
|
||||
// In performs an incoming transfer with the server in a.
|
||||
// If you would like to set the source IP, or some other attribute
|
||||
// of a Dialer for a Transfer, you can do so by specifying the attributes
|
||||
// in the Transfer.Conn:
|
||||
//
|
||||
// d := net.Dialer{LocalAddr: transfer_source}
|
||||
// con, err := d.Dial("tcp", master)
|
||||
// dnscon := &dns.Conn{Conn:con}
|
||||
// transfer = &dns.Transfer{Conn: dnscon}
|
||||
// channel, err := transfer.In(message, master)
|
||||
//
|
||||
func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
|
||||
timeout := dnsTimeout
|
||||
if t.DialTimeout != 0 {
|
||||
timeout = t.DialTimeout
|
||||
}
|
||||
t.Conn, err = DialTimeout("tcp", a, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if t.Conn == nil {
|
||||
t.Conn, err = DialTimeout("tcp", a, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := t.WriteMsg(q); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -91,7 +103,6 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
|
|||
c <- &Envelope{in.Answer, nil}
|
||||
}
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getIP(s string) string {
|
||||
a, err := net.LookupAddr(s)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return a[0]
|
||||
}
|
||||
|
||||
// flaky, need to setup local server and test from
|
||||
// that.
|
||||
func testClientAXFR(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
m := new(Msg)
|
||||
m.SetAxfr("miek.nl.")
|
||||
|
||||
server := getIP("linode.atoom.net")
|
||||
|
||||
tr := new(Transfer)
|
||||
|
||||
if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
|
||||
t.Fatal("failed to setup axfr: ", err)
|
||||
} else {
|
||||
for ex := range a {
|
||||
if ex.Error != nil {
|
||||
t.Errorf("error %v", ex.Error)
|
||||
break
|
||||
}
|
||||
for _, rr := range ex.RR {
|
||||
t.Log(rr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fails.
|
||||
func testClientAXFRMultipleEnvelopes(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
m := new(Msg)
|
||||
m.SetAxfr("nlnetlabs.nl.")
|
||||
|
||||
server := getIP("open.nlnetlabs.nl.")
|
||||
|
||||
tr := new(Transfer)
|
||||
if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
|
||||
t.Fatalf("Failed to setup axfr %v for server: %v", err, server)
|
||||
} else {
|
||||
for ex := range a {
|
||||
if ex.Error != nil {
|
||||
t.Errorf("Error %v", ex.Error)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testClientTsigAXFR(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
m := new(Msg)
|
||||
m.SetAxfr("example.nl.")
|
||||
m.SetTsig("axfr.", HmacMD5, 300, time.Now().Unix())
|
||||
|
||||
tr := new(Transfer)
|
||||
tr.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||
|
||||
if a, err := tr.In(m, "176.58.119.54:53"); err != nil {
|
||||
t.Fatal("failed to setup axfr: ", err)
|
||||
} else {
|
||||
for ex := range a {
|
||||
if ex.Error != nil {
|
||||
t.Errorf("error %v", ex.Error)
|
||||
break
|
||||
}
|
||||
for _, rr := range ex.RR {
|
||||
t.Log(rr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -144,8 +144,10 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
|
|||
//
|
||||
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
|
||||
// if x.Error != nil {
|
||||
// // Do something with x.RR
|
||||
// }
|
||||
// // log.Println(x.Error)
|
||||
// } else {
|
||||
// // Do something with x.RR
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Comments specified after an RR (and on the same line!) are returned too:
|
||||
|
|
|
|||
|
|
@ -896,22 +896,24 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
|||
if l.length == 0 {
|
||||
return rr, nil, ""
|
||||
}
|
||||
if i, e := strconv.Atoi(l.token); e != nil || l.err {
|
||||
i, e := strconv.Atoi(l.token)
|
||||
if e != nil || l.err {
|
||||
return nil, &ParseError{f, "bad LOC Latitude", l}, ""
|
||||
} else {
|
||||
rr.Latitude = 1000 * 60 * 60 * uint32(i)
|
||||
}
|
||||
rr.Latitude = 1000 * 60 * 60 * uint32(i)
|
||||
|
||||
<-c // zBlank
|
||||
// Either number, 'N' or 'S'
|
||||
l = <-c
|
||||
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
|
||||
goto East
|
||||
}
|
||||
if i, e := strconv.Atoi(l.token); e != nil || l.err {
|
||||
i, e = strconv.Atoi(l.token)
|
||||
if e != nil || l.err {
|
||||
return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
|
||||
} else {
|
||||
rr.Latitude += 1000 * 60 * uint32(i)
|
||||
}
|
||||
rr.Latitude += 1000 * 60 * uint32(i)
|
||||
|
||||
<-c // zBlank
|
||||
l = <-c
|
||||
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
|
||||
|
|
@ -1484,11 +1486,11 @@ func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
|||
// Ok
|
||||
case zString:
|
||||
if k, err = net.LookupPort(proto, l.token); err != nil {
|
||||
if i, e := strconv.Atoi(l.token); e != nil { // If a number use that
|
||||
i, e := strconv.Atoi(l.token) // If a number use that
|
||||
if e != nil {
|
||||
return nil, &ParseError{f, "bad WKS BitMap", l}, ""
|
||||
} else {
|
||||
rr.BitMap = append(rr.BitMap, uint16(i))
|
||||
}
|
||||
rr.BitMap = append(rr.BitMap, uint16(i))
|
||||
}
|
||||
rr.BitMap = append(rr.BitMap, uint16(k))
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,842 @@
|
|||
// *** DO NOT MODIFY ***
|
||||
// AUTOGENERATED BY go generate
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net"
|
||||
)
|
||||
|
||||
// TypeToRR is a map of constructors for each RR type.
|
||||
var TypeToRR = map[uint16]func() RR{
|
||||
TypeA: func() RR { return new(A) },
|
||||
TypeAAAA: func() RR { return new(AAAA) },
|
||||
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||
TypeANY: func() RR { return new(ANY) },
|
||||
TypeCAA: func() RR { return new(CAA) },
|
||||
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
|
||||
TypeCDS: func() RR { return new(CDS) },
|
||||
TypeCERT: func() RR { return new(CERT) },
|
||||
TypeCNAME: func() RR { return new(CNAME) },
|
||||
TypeDHCID: func() RR { return new(DHCID) },
|
||||
TypeDLV: func() RR { return new(DLV) },
|
||||
TypeDNAME: func() RR { return new(DNAME) },
|
||||
TypeDNSKEY: func() RR { return new(DNSKEY) },
|
||||
TypeDS: func() RR { return new(DS) },
|
||||
TypeEID: func() RR { return new(EID) },
|
||||
TypeEUI48: func() RR { return new(EUI48) },
|
||||
TypeEUI64: func() RR { return new(EUI64) },
|
||||
TypeGID: func() RR { return new(GID) },
|
||||
TypeGPOS: func() RR { return new(GPOS) },
|
||||
TypeHINFO: func() RR { return new(HINFO) },
|
||||
TypeHIP: func() RR { return new(HIP) },
|
||||
TypeIPSECKEY: func() RR { return new(IPSECKEY) },
|
||||
TypeKEY: func() RR { return new(KEY) },
|
||||
TypeKX: func() RR { return new(KX) },
|
||||
TypeL32: func() RR { return new(L32) },
|
||||
TypeL64: func() RR { return new(L64) },
|
||||
TypeLOC: func() RR { return new(LOC) },
|
||||
TypeLP: func() RR { return new(LP) },
|
||||
TypeMB: func() RR { return new(MB) },
|
||||
TypeMD: func() RR { return new(MD) },
|
||||
TypeMF: func() RR { return new(MF) },
|
||||
TypeMG: func() RR { return new(MG) },
|
||||
TypeMINFO: func() RR { return new(MINFO) },
|
||||
TypeMR: func() RR { return new(MR) },
|
||||
TypeMX: func() RR { return new(MX) },
|
||||
TypeNAPTR: func() RR { return new(NAPTR) },
|
||||
TypeNID: func() RR { return new(NID) },
|
||||
TypeNIMLOC: func() RR { return new(NIMLOC) },
|
||||
TypeNINFO: func() RR { return new(NINFO) },
|
||||
TypeNS: func() RR { return new(NS) },
|
||||
TypeNSAPPTR: func() RR { return new(NSAPPTR) },
|
||||
TypeNSEC: func() RR { return new(NSEC) },
|
||||
TypeNSEC3: func() RR { return new(NSEC3) },
|
||||
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
|
||||
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
|
||||
TypeOPT: func() RR { return new(OPT) },
|
||||
TypePTR: func() RR { return new(PTR) },
|
||||
TypePX: func() RR { return new(PX) },
|
||||
TypeRKEY: func() RR { return new(RKEY) },
|
||||
TypeRP: func() RR { return new(RP) },
|
||||
TypeRRSIG: func() RR { return new(RRSIG) },
|
||||
TypeRT: func() RR { return new(RT) },
|
||||
TypeSIG: func() RR { return new(SIG) },
|
||||
TypeSOA: func() RR { return new(SOA) },
|
||||
TypeSPF: func() RR { return new(SPF) },
|
||||
TypeSRV: func() RR { return new(SRV) },
|
||||
TypeSSHFP: func() RR { return new(SSHFP) },
|
||||
TypeTA: func() RR { return new(TA) },
|
||||
TypeTALINK: func() RR { return new(TALINK) },
|
||||
TypeTKEY: func() RR { return new(TKEY) },
|
||||
TypeTLSA: func() RR { return new(TLSA) },
|
||||
TypeTSIG: func() RR { return new(TSIG) },
|
||||
TypeTXT: func() RR { return new(TXT) },
|
||||
TypeUID: func() RR { return new(UID) },
|
||||
TypeUINFO: func() RR { return new(UINFO) },
|
||||
TypeURI: func() RR { return new(URI) },
|
||||
TypeWKS: func() RR { return new(WKS) },
|
||||
TypeX25: func() RR { return new(X25) },
|
||||
}
|
||||
|
||||
// TypeToString is a map of strings for each RR type.
|
||||
var TypeToString = map[uint16]string{
|
||||
TypeA: "A",
|
||||
TypeAAAA: "AAAA",
|
||||
TypeAFSDB: "AFSDB",
|
||||
TypeANY: "ANY",
|
||||
TypeATMA: "ATMA",
|
||||
TypeAXFR: "AXFR",
|
||||
TypeCAA: "CAA",
|
||||
TypeCDNSKEY: "CDNSKEY",
|
||||
TypeCDS: "CDS",
|
||||
TypeCERT: "CERT",
|
||||
TypeCNAME: "CNAME",
|
||||
TypeDHCID: "DHCID",
|
||||
TypeDLV: "DLV",
|
||||
TypeDNAME: "DNAME",
|
||||
TypeDNSKEY: "DNSKEY",
|
||||
TypeDS: "DS",
|
||||
TypeEID: "EID",
|
||||
TypeEUI48: "EUI48",
|
||||
TypeEUI64: "EUI64",
|
||||
TypeGID: "GID",
|
||||
TypeGPOS: "GPOS",
|
||||
TypeHINFO: "HINFO",
|
||||
TypeHIP: "HIP",
|
||||
TypeIPSECKEY: "IPSECKEY",
|
||||
TypeISDN: "ISDN",
|
||||
TypeIXFR: "IXFR",
|
||||
TypeKEY: "KEY",
|
||||
TypeKX: "KX",
|
||||
TypeL32: "L32",
|
||||
TypeL64: "L64",
|
||||
TypeLOC: "LOC",
|
||||
TypeLP: "LP",
|
||||
TypeMAILA: "MAILA",
|
||||
TypeMAILB: "MAILB",
|
||||
TypeMB: "MB",
|
||||
TypeMD: "MD",
|
||||
TypeMF: "MF",
|
||||
TypeMG: "MG",
|
||||
TypeMINFO: "MINFO",
|
||||
TypeMR: "MR",
|
||||
TypeMX: "MX",
|
||||
TypeNAPTR: "NAPTR",
|
||||
TypeNID: "NID",
|
||||
TypeNIMLOC: "NIMLOC",
|
||||
TypeNINFO: "NINFO",
|
||||
TypeNS: "NS",
|
||||
TypeNSEC: "NSEC",
|
||||
TypeNSEC3: "NSEC3",
|
||||
TypeNSEC3PARAM: "NSEC3PARAM",
|
||||
TypeNULL: "NULL",
|
||||
TypeNXT: "NXT",
|
||||
TypeNone: "None",
|
||||
TypeOPENPGPKEY: "OPENPGPKEY",
|
||||
TypeOPT: "OPT",
|
||||
TypePTR: "PTR",
|
||||
TypePX: "PX",
|
||||
TypeRKEY: "RKEY",
|
||||
TypeRP: "RP",
|
||||
TypeRRSIG: "RRSIG",
|
||||
TypeRT: "RT",
|
||||
TypeReserved: "Reserved",
|
||||
TypeSIG: "SIG",
|
||||
TypeSOA: "SOA",
|
||||
TypeSPF: "SPF",
|
||||
TypeSRV: "SRV",
|
||||
TypeSSHFP: "SSHFP",
|
||||
TypeTA: "TA",
|
||||
TypeTALINK: "TALINK",
|
||||
TypeTKEY: "TKEY",
|
||||
TypeTLSA: "TLSA",
|
||||
TypeTSIG: "TSIG",
|
||||
TypeTXT: "TXT",
|
||||
TypeUID: "UID",
|
||||
TypeUINFO: "UINFO",
|
||||
TypeUNSPEC: "UNSPEC",
|
||||
TypeURI: "URI",
|
||||
TypeWKS: "WKS",
|
||||
TypeX25: "X25",
|
||||
TypeNSAPPTR: "NSAP-PTR",
|
||||
}
|
||||
|
||||
// Header() functions
|
||||
func (rr *A) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *GID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *LP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MD) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TSIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *UID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *URI) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *X25) Header() *RR_Header { return &rr.Hdr }
|
||||
|
||||
// len() functions
|
||||
func (rr *A) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += net.IPv4len // A
|
||||
return l
|
||||
}
|
||||
func (rr *AAAA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += net.IPv6len // AAAA
|
||||
return l
|
||||
}
|
||||
func (rr *AFSDB) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Subtype
|
||||
l += len(rr.Hostname) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *ANY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
return l
|
||||
}
|
||||
func (rr *CAA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Flag
|
||||
l += len(rr.Tag) + 1
|
||||
l += len(rr.Value)
|
||||
return l
|
||||
}
|
||||
func (rr *CERT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Type
|
||||
l += 2 // KeyTag
|
||||
l += 1 // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
||||
return l
|
||||
}
|
||||
func (rr *CNAME) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Target) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *DHCID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Digest))
|
||||
return l
|
||||
}
|
||||
func (rr *DNAME) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Target) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *DNSKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Flags
|
||||
l += 1 // Protocol
|
||||
l += 1 // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *DS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // KeyTag
|
||||
l += 1 // Algorithm
|
||||
l += 1 // DigestType
|
||||
l += len(rr.Digest)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *EID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Endpoint)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *EUI48) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 6 // Address
|
||||
return l
|
||||
}
|
||||
func (rr *EUI64) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 8 // Address
|
||||
return l
|
||||
}
|
||||
func (rr *GID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 4 // Gid
|
||||
return l
|
||||
}
|
||||
func (rr *GPOS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Longitude) + 1
|
||||
l += len(rr.Latitude) + 1
|
||||
l += len(rr.Altitude) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *HINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Cpu) + 1
|
||||
l += len(rr.Os) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *HIP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // HitLength
|
||||
l += 1 // PublicKeyAlgorithm
|
||||
l += 2 // PublicKeyLength
|
||||
l += len(rr.Hit)/2 + 1
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
for _, x := range rr.RendezvousServers {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *KX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Exchanger) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *L32) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += net.IPv4len // Locator32
|
||||
return l
|
||||
}
|
||||
func (rr *L64) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += 8 // Locator64
|
||||
return l
|
||||
}
|
||||
func (rr *LOC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Version
|
||||
l += 1 // Size
|
||||
l += 1 // HorizPre
|
||||
l += 1 // VertPre
|
||||
l += 4 // Latitude
|
||||
l += 4 // Longitude
|
||||
l += 4 // Altitude
|
||||
return l
|
||||
}
|
||||
func (rr *LP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Fqdn) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MB) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mb) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MD) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Md) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mf) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mg) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Rmail) + 1
|
||||
l += len(rr.Email) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mr) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Mx) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NAPTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Order
|
||||
l += 2 // Preference
|
||||
l += len(rr.Flags) + 1
|
||||
l += len(rr.Service) + 1
|
||||
l += len(rr.Regexp) + 1
|
||||
l += len(rr.Replacement) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += 8 // NodeID
|
||||
return l
|
||||
}
|
||||
func (rr *NIMLOC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Locator)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, x := range rr.ZSData {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *NS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ns) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NSAPPTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ptr) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NSEC3PARAM) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Hash
|
||||
l += 1 // Flags
|
||||
l += 2 // Iterations
|
||||
l += 1 // SaltLength
|
||||
l += len(rr.Salt)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *OPENPGPKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *PTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ptr) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *PX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Map822) + 1
|
||||
l += len(rr.Mapx400) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *RFC3597) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Rdata)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *RKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Flags
|
||||
l += 1 // Protocol
|
||||
l += 1 // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *RP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mbox) + 1
|
||||
l += len(rr.Txt) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *RRSIG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // TypeCovered
|
||||
l += 1 // Algorithm
|
||||
l += 1 // Labels
|
||||
l += 4 // OrigTtl
|
||||
l += 4 // Expiration
|
||||
l += 4 // Inception
|
||||
l += 2 // KeyTag
|
||||
l += len(rr.SignerName) + 1
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Signature))
|
||||
return l
|
||||
}
|
||||
func (rr *RT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Host) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *SOA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ns) + 1
|
||||
l += len(rr.Mbox) + 1
|
||||
l += 4 // Serial
|
||||
l += 4 // Refresh
|
||||
l += 4 // Retry
|
||||
l += 4 // Expire
|
||||
l += 4 // Minttl
|
||||
return l
|
||||
}
|
||||
func (rr *SPF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *SRV) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Priority
|
||||
l += 2 // Weight
|
||||
l += 2 // Port
|
||||
l += len(rr.Target) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *SSHFP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Algorithm
|
||||
l += 1 // Type
|
||||
l += len(rr.FingerPrint)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // KeyTag
|
||||
l += 1 // Algorithm
|
||||
l += 1 // DigestType
|
||||
l += len(rr.Digest)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TALINK) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.PreviousName) + 1
|
||||
l += len(rr.NextName) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Algorithm) + 1
|
||||
l += 4 // Inception
|
||||
l += 4 // Expiration
|
||||
l += 2 // Mode
|
||||
l += 2 // Error
|
||||
l += 2 // KeySize
|
||||
l += len(rr.Key) + 1
|
||||
l += 2 // OtherLen
|
||||
l += len(rr.OtherData) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TLSA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Usage
|
||||
l += 1 // Selector
|
||||
l += 1 // MatchingType
|
||||
l += len(rr.Certificate)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TSIG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Algorithm) + 1
|
||||
l += 6 // TimeSigned
|
||||
l += 2 // Fudge
|
||||
l += 2 // MACSize
|
||||
l += len(rr.MAC)/2 + 1
|
||||
l += 2 // OrigId
|
||||
l += 2 // Error
|
||||
l += 2 // OtherLen
|
||||
l += len(rr.OtherData)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TXT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *UID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 4 // Uid
|
||||
return l
|
||||
}
|
||||
func (rr *UINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Uinfo) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *URI) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Priority
|
||||
l += 2 // Weight
|
||||
l += len(rr.Target)
|
||||
return l
|
||||
}
|
||||
func (rr *X25) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.PSDNAddress) + 1
|
||||
return l
|
||||
}
|
||||
|
||||
// copy() functions
|
||||
func (rr *A) copy() RR {
|
||||
return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)}
|
||||
}
|
||||
func (rr *AAAA) copy() RR {
|
||||
return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)}
|
||||
}
|
||||
func (rr *AFSDB) copy() RR {
|
||||
return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname}
|
||||
}
|
||||
func (rr *ANY) copy() RR {
|
||||
return &ANY{*rr.Hdr.copyHeader()}
|
||||
}
|
||||
func (rr *CAA) copy() RR {
|
||||
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
|
||||
}
|
||||
func (rr *CERT) copy() RR {
|
||||
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
|
||||
}
|
||||
func (rr *CNAME) copy() RR {
|
||||
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||
}
|
||||
func (rr *DHCID) copy() RR {
|
||||
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
||||
}
|
||||
func (rr *DNAME) copy() RR {
|
||||
return &DNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||
}
|
||||
func (rr *DNSKEY) copy() RR {
|
||||
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
func (rr *DS) copy() RR {
|
||||
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
func (rr *EID) copy() RR {
|
||||
return &EID{*rr.Hdr.copyHeader(), rr.Endpoint}
|
||||
}
|
||||
func (rr *EUI48) copy() RR {
|
||||
return &EUI48{*rr.Hdr.copyHeader(), rr.Address}
|
||||
}
|
||||
func (rr *EUI64) copy() RR {
|
||||
return &EUI64{*rr.Hdr.copyHeader(), rr.Address}
|
||||
}
|
||||
func (rr *GID) copy() RR {
|
||||
return &GID{*rr.Hdr.copyHeader(), rr.Gid}
|
||||
}
|
||||
func (rr *GPOS) copy() RR {
|
||||
return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude}
|
||||
}
|
||||
func (rr *HINFO) copy() RR {
|
||||
return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os}
|
||||
}
|
||||
func (rr *HIP) copy() RR {
|
||||
RendezvousServers := make([]string, len(rr.RendezvousServers))
|
||||
copy(RendezvousServers, rr.RendezvousServers)
|
||||
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
|
||||
}
|
||||
func (rr *IPSECKEY) copy() RR {
|
||||
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, copyIP(rr.GatewayA), copyIP(rr.GatewayAAAA), rr.GatewayName, rr.PublicKey}
|
||||
}
|
||||
func (rr *KX) copy() RR {
|
||||
return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger}
|
||||
}
|
||||
func (rr *L32) copy() RR {
|
||||
return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)}
|
||||
}
|
||||
func (rr *L64) copy() RR {
|
||||
return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64}
|
||||
}
|
||||
func (rr *LOC) copy() RR {
|
||||
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
|
||||
}
|
||||
func (rr *LP) copy() RR {
|
||||
return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn}
|
||||
}
|
||||
func (rr *MB) copy() RR {
|
||||
return &MB{*rr.Hdr.copyHeader(), rr.Mb}
|
||||
}
|
||||
func (rr *MD) copy() RR {
|
||||
return &MD{*rr.Hdr.copyHeader(), rr.Md}
|
||||
}
|
||||
func (rr *MF) copy() RR {
|
||||
return &MF{*rr.Hdr.copyHeader(), rr.Mf}
|
||||
}
|
||||
func (rr *MG) copy() RR {
|
||||
return &MG{*rr.Hdr.copyHeader(), rr.Mg}
|
||||
}
|
||||
func (rr *MINFO) copy() RR {
|
||||
return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email}
|
||||
}
|
||||
func (rr *MR) copy() RR {
|
||||
return &MR{*rr.Hdr.copyHeader(), rr.Mr}
|
||||
}
|
||||
func (rr *MX) copy() RR {
|
||||
return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx}
|
||||
}
|
||||
func (rr *NAPTR) copy() RR {
|
||||
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
|
||||
}
|
||||
func (rr *NID) copy() RR {
|
||||
return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID}
|
||||
}
|
||||
func (rr *NIMLOC) copy() RR {
|
||||
return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator}
|
||||
}
|
||||
func (rr *NINFO) copy() RR {
|
||||
ZSData := make([]string, len(rr.ZSData))
|
||||
copy(ZSData, rr.ZSData)
|
||||
return &NINFO{*rr.Hdr.copyHeader(), ZSData}
|
||||
}
|
||||
func (rr *NS) copy() RR {
|
||||
return &NS{*rr.Hdr.copyHeader(), rr.Ns}
|
||||
}
|
||||
func (rr *NSAPPTR) copy() RR {
|
||||
return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||
}
|
||||
func (rr *NSEC) copy() RR {
|
||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||
copy(TypeBitMap, rr.TypeBitMap)
|
||||
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap}
|
||||
}
|
||||
func (rr *NSEC3) copy() RR {
|
||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||
copy(TypeBitMap, rr.TypeBitMap)
|
||||
return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
|
||||
}
|
||||
func (rr *NSEC3PARAM) copy() RR {
|
||||
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
||||
}
|
||||
func (rr *OPENPGPKEY) copy() RR {
|
||||
return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey}
|
||||
}
|
||||
func (rr *OPT) copy() RR {
|
||||
Option := make([]EDNS0, len(rr.Option))
|
||||
copy(Option, rr.Option)
|
||||
return &OPT{*rr.Hdr.copyHeader(), Option}
|
||||
}
|
||||
func (rr *PTR) copy() RR {
|
||||
return &PTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||
}
|
||||
func (rr *PX) copy() RR {
|
||||
return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400}
|
||||
}
|
||||
func (rr *RFC3597) copy() RR {
|
||||
return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata}
|
||||
}
|
||||
func (rr *RKEY) copy() RR {
|
||||
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
func (rr *RP) copy() RR {
|
||||
return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt}
|
||||
}
|
||||
func (rr *RRSIG) copy() RR {
|
||||
return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
|
||||
}
|
||||
func (rr *RT) copy() RR {
|
||||
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
|
||||
}
|
||||
func (rr *SOA) copy() RR {
|
||||
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
||||
}
|
||||
func (rr *SPF) copy() RR {
|
||||
Txt := make([]string, len(rr.Txt))
|
||||
copy(Txt, rr.Txt)
|
||||
return &SPF{*rr.Hdr.copyHeader(), Txt}
|
||||
}
|
||||
func (rr *SRV) copy() RR {
|
||||
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
|
||||
}
|
||||
func (rr *SSHFP) copy() RR {
|
||||
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
|
||||
}
|
||||
func (rr *TA) copy() RR {
|
||||
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
func (rr *TALINK) copy() RR {
|
||||
return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName}
|
||||
}
|
||||
func (rr *TKEY) copy() RR {
|
||||
return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
|
||||
}
|
||||
func (rr *TLSA) copy() RR {
|
||||
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
||||
}
|
||||
func (rr *TSIG) copy() RR {
|
||||
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
||||
}
|
||||
func (rr *TXT) copy() RR {
|
||||
Txt := make([]string, len(rr.Txt))
|
||||
copy(Txt, rr.Txt)
|
||||
return &TXT{*rr.Hdr.copyHeader(), Txt}
|
||||
}
|
||||
func (rr *UID) copy() RR {
|
||||
return &UID{*rr.Hdr.copyHeader(), rr.Uid}
|
||||
}
|
||||
func (rr *UINFO) copy() RR {
|
||||
return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo}
|
||||
}
|
||||
func (rr *URI) copy() RR {
|
||||
return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target}
|
||||
}
|
||||
func (rr *WKS) copy() RR {
|
||||
BitMap := make([]uint16, len(rr.BitMap))
|
||||
copy(BitMap, rr.BitMap)
|
||||
return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, BitMap}
|
||||
}
|
||||
func (rr *X25) copy() RR {
|
||||
return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
|
||||
}
|
||||
33
README.md
33
README.md
|
|
@ -40,6 +40,10 @@ CentOS:
|
|||
|
||||
sudo yum install libtool-ltdl-devel MariaDB-server MariaDB-client rabbitmq-server
|
||||
|
||||
Arch Linux:
|
||||
|
||||
sudo pacman -S libtool mariadb rabbitmq --needed
|
||||
|
||||
OS X:
|
||||
|
||||
brew install libtool mariadb rabbitmq
|
||||
|
|
@ -49,25 +53,34 @@ or
|
|||
sudo port install libtool mariadb-server rabbitmq-server
|
||||
|
||||
(On OS X, using port, you will have to add `CGO_CFLAGS="-I/opt/local/include" CGO_LDFLAGS="-L/opt/local/lib"` to your environment or `go` invocations.)
|
||||
|
||||
|
||||
Resolve Go-dependencies:
|
||||
|
||||
> go get bitbucket.org/liamstask/goose/cmd/goose
|
||||
> go get github.com/jsha/listenbuddy
|
||||
> go get github.com/letsencrypt/boulder/ # Ignore errors about no buildable files
|
||||
> go get -u github.com/golang/lint/golint
|
||||
|
||||
Set up a database:
|
||||
|
||||
> cd $GOPATH/src/github.com/letsencrypt/boulder
|
||||
> ./test/create_db.sh
|
||||
# This starts each Boulder component with test configs. Ctrl-C kills all.
|
||||
> ./start.py
|
||||
# Run tests
|
||||
> go get -u github.com/golang/lint/golint
|
||||
> ./test.sh
|
||||
|
||||
Note: `create_db.sh` it uses the root MariaDB user with the default
|
||||
**Note**: `create_db.sh` uses the root MariaDB user with the default
|
||||
password, so if you have disabled that account or changed the password
|
||||
you may have to adjust the file or recreate the commands.
|
||||
|
||||
You can also check out the official client from
|
||||
https://github.com/letsencrypt/letsencrypt/ and follow the setup
|
||||
instructions there.
|
||||
Start each boulder component with test configs (Ctrl-C kills all):
|
||||
|
||||
> ./start.py
|
||||
|
||||
Run tests:
|
||||
|
||||
> ./test.sh
|
||||
|
||||
Working with a client:
|
||||
|
||||
Check out the official Let's Encrypt client from https://github.com/letsencrypt/letsencrypt/ and follow the setup instructions there.
|
||||
|
||||
Component Model
|
||||
---------------
|
||||
|
|
|
|||
109
rpc/amqp-rpc.go
109
rpc/amqp-rpc.go
|
|
@ -9,6 +9,7 @@ import (
|
|||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -219,79 +220,101 @@ type rpcError struct {
|
|||
|
||||
// Wraps a error in a rpcError so it can be marshalled to
|
||||
// JSON.
|
||||
func wrapError(err error) (rpcError rpcError) {
|
||||
func wrapError(err error) *rpcError {
|
||||
if err != nil {
|
||||
rpcError.Value = err.Error()
|
||||
wrapped := &rpcError{
|
||||
Value: err.Error(),
|
||||
}
|
||||
switch err.(type) {
|
||||
case core.InternalServerError:
|
||||
rpcError.Type = "InternalServerError"
|
||||
wrapped.Type = "InternalServerError"
|
||||
case core.NotSupportedError:
|
||||
rpcError.Type = "NotSupportedError"
|
||||
wrapped.Type = "NotSupportedError"
|
||||
case core.MalformedRequestError:
|
||||
rpcError.Type = "MalformedRequestError"
|
||||
wrapped.Type = "MalformedRequestError"
|
||||
case core.UnauthorizedError:
|
||||
rpcError.Type = "UnauthorizedError"
|
||||
wrapped.Type = "UnauthorizedError"
|
||||
case core.NotFoundError:
|
||||
rpcError.Type = "NotFoundError"
|
||||
wrapped.Type = "NotFoundError"
|
||||
case core.SyntaxError:
|
||||
rpcError.Type = "SyntaxError"
|
||||
wrapped.Type = "SyntaxError"
|
||||
case core.SignatureValidationError:
|
||||
rpcError.Type = "SignatureValidationError"
|
||||
wrapped.Type = "SignatureValidationError"
|
||||
case core.CertificateIssuanceError:
|
||||
rpcError.Type = "CertificateIssuanceError"
|
||||
wrapped.Type = "CertificateIssuanceError"
|
||||
case core.NoSuchRegistrationError:
|
||||
rpcError.Type = "NoSuchRegistrationError"
|
||||
wrapped.Type = "NoSuchRegistrationError"
|
||||
case core.TooManyRPCRequestsError:
|
||||
rpcError.Type = "TooManyRPCRequestsError"
|
||||
wrapped.Type = "TooManyRPCRequestsError"
|
||||
case core.RateLimitedError:
|
||||
rpcError.Type = "RateLimitedError"
|
||||
wrapped.Type = "RateLimitedError"
|
||||
case core.ServiceUnavailableError:
|
||||
rpcError.Type = "ServiceUnavailableError"
|
||||
wrapped.Type = "ServiceUnavailableError"
|
||||
}
|
||||
return wrapped
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unwraps a rpcError and returns the correct error type.
|
||||
func unwrapError(rpcError rpcError) (err error) {
|
||||
if rpcError.Value != "" {
|
||||
func unwrapError(rpcError *rpcError) error {
|
||||
if rpcError != nil {
|
||||
switch rpcError.Type {
|
||||
case "InternalServerError":
|
||||
err = core.InternalServerError(rpcError.Value)
|
||||
return core.InternalServerError(rpcError.Value)
|
||||
case "NotSupportedError":
|
||||
err = core.NotSupportedError(rpcError.Value)
|
||||
return core.NotSupportedError(rpcError.Value)
|
||||
case "MalformedRequestError":
|
||||
err = core.MalformedRequestError(rpcError.Value)
|
||||
return core.MalformedRequestError(rpcError.Value)
|
||||
case "UnauthorizedError":
|
||||
err = core.UnauthorizedError(rpcError.Value)
|
||||
return core.UnauthorizedError(rpcError.Value)
|
||||
case "NotFoundError":
|
||||
err = core.NotFoundError(rpcError.Value)
|
||||
return core.NotFoundError(rpcError.Value)
|
||||
case "SyntaxError":
|
||||
err = core.SyntaxError(rpcError.Value)
|
||||
return core.SyntaxError(rpcError.Value)
|
||||
case "SignatureValidationError":
|
||||
err = core.SignatureValidationError(rpcError.Value)
|
||||
return core.SignatureValidationError(rpcError.Value)
|
||||
case "CertificateIssuanceError":
|
||||
err = core.CertificateIssuanceError(rpcError.Value)
|
||||
return core.CertificateIssuanceError(rpcError.Value)
|
||||
case "NoSuchRegistrationError":
|
||||
err = core.NoSuchRegistrationError(rpcError.Value)
|
||||
return core.NoSuchRegistrationError(rpcError.Value)
|
||||
case "TooManyRPCRequestsError":
|
||||
err = core.TooManyRPCRequestsError(rpcError.Value)
|
||||
return core.TooManyRPCRequestsError(rpcError.Value)
|
||||
case "RateLimitedError":
|
||||
err = core.RateLimitedError(rpcError.Value)
|
||||
return core.RateLimitedError(rpcError.Value)
|
||||
case "ServiceUnavailableError":
|
||||
err = core.ServiceUnavailableError(rpcError.Value)
|
||||
return core.ServiceUnavailableError(rpcError.Value)
|
||||
default:
|
||||
err = errors.New(rpcError.Value)
|
||||
return errors.New(rpcError.Value)
|
||||
}
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// rpcResponse is a stuct for wire-representation of response messages
|
||||
// used by DispatchSync
|
||||
type rpcResponse struct {
|
||||
ReturnVal []byte `json:"returnVal,omitempty"`
|
||||
Error rpcError `json:"error,omitempty"`
|
||||
ReturnVal []byte `json:"returnVal"`
|
||||
Error *rpcError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Hack: Some of our RPCs return DER directly. If we log it naively it will
|
||||
// just be a bunch of numbers. It's easy to detect DER, so we use this function
|
||||
// before logging to base64-encode anything that looks like DER.
|
||||
func safeDER(input []byte) string {
|
||||
if len(input) > 0 && input[0] == 0x30 {
|
||||
return string(base64.RawStdEncoding.EncodeToString(input))
|
||||
}
|
||||
return string(input)
|
||||
}
|
||||
|
||||
// Used for debug logging
|
||||
func (r rpcResponse) debugString() string {
|
||||
ret := safeDER(r.ReturnVal)
|
||||
if r.Error == nil {
|
||||
return ret
|
||||
}
|
||||
return fmt.Sprintf("%s, RPCERR: %s", ret, r.Error)
|
||||
}
|
||||
|
||||
// AmqpChannel sets a AMQP connection up using SSL if configuration is provided
|
||||
|
|
@ -370,10 +393,10 @@ func AmqpChannel(conf cmd.Config) (*amqp.Channel, error) {
|
|||
func (rpc *AmqpRPCServer) processMessage(msg amqp.Delivery) {
|
||||
// XXX-JWS: jws.Verify(body)
|
||||
cb, present := rpc.dispatchTable[msg.Type]
|
||||
rpc.log.Info(fmt.Sprintf(" [s<][%s][%s] received %s(%s) [%s]", rpc.serverQueue, msg.ReplyTo, msg.Type, core.B64enc(msg.Body), msg.CorrelationId))
|
||||
rpc.log.Info(fmt.Sprintf(" [s<][%s][%s] received %s(%s) [%s]", rpc.serverQueue, msg.ReplyTo, msg.Type, safeDER(msg.Body), msg.CorrelationId))
|
||||
if !present {
|
||||
// AUDIT[ Misrouted Messages ] f523f21f-12d2-4c31-b2eb-ee4b7d96d60e
|
||||
rpc.log.Audit(fmt.Sprintf(" [s<][%s][%s] Misrouted message: %s - %s - %s", rpc.serverQueue, msg.ReplyTo, msg.Type, core.B64enc(msg.Body), msg.CorrelationId))
|
||||
rpc.log.Audit(fmt.Sprintf(" [s<][%s][%s] Misrouted message: %s - %s - %s", rpc.serverQueue, msg.ReplyTo, msg.Type, safeDER(msg.Body), msg.CorrelationId))
|
||||
return
|
||||
}
|
||||
var response rpcResponse
|
||||
|
|
@ -386,10 +409,7 @@ func (rpc *AmqpRPCServer) processMessage(msg amqp.Delivery) {
|
|||
rpc.log.Audit(fmt.Sprintf(" [s>][%s][%s] Error condition marshalling RPC response %s [%s]", rpc.serverQueue, msg.ReplyTo, msg.Type, msg.CorrelationId))
|
||||
return
|
||||
}
|
||||
if response.Error.Value != "" {
|
||||
rpc.log.Info(fmt.Sprintf(" [s>][%s][%s] %s failed, replying: %s (%s) [%s]", rpc.serverQueue, msg.ReplyTo, msg.Type, response.Error.Value, response.Error.Type, msg.CorrelationId))
|
||||
}
|
||||
rpc.log.Debug(fmt.Sprintf(" [s>][%s][%s] replying %s(%s) [%s]", rpc.serverQueue, msg.ReplyTo, msg.Type, core.B64enc(jsonResponse), msg.CorrelationId))
|
||||
rpc.log.Debug(fmt.Sprintf(" [s>][%s][%s] replying %s: %s [%s]", rpc.serverQueue, msg.ReplyTo, msg.Type, response.debugString(), msg.CorrelationId))
|
||||
rpc.connection.publish(
|
||||
msg.ReplyTo,
|
||||
msg.CorrelationId,
|
||||
|
|
@ -584,7 +604,6 @@ func NewAmqpRPCClient(clientQueuePrefix, serverQueue string, c cmd.Config, stats
|
|||
continue
|
||||
}
|
||||
|
||||
rpc.log.Debug(fmt.Sprintf(" [c<][%s] response %s(%s) [%s]", clientQueue, msg.Type, core.B64enc(msg.Body), corrID))
|
||||
responseChan <- msg.Body
|
||||
rpc.mu.Lock()
|
||||
delete(rpc.pending, corrID)
|
||||
|
|
@ -618,13 +637,18 @@ func (rpc *AmqpRPCCLient) dispatch(method string, body []byte) (string, chan []b
|
|||
// At least in some cases, it's important that this channel
|
||||
// be buffered to avoid deadlock
|
||||
responseChan := make(chan []byte, 1)
|
||||
corrID := core.NewToken()
|
||||
corrIDBytes := make([]byte, 8)
|
||||
_, err := rand.Read(corrIDBytes)
|
||||
if err != nil {
|
||||
panic("randomness failed")
|
||||
}
|
||||
corrID := base64.RawURLEncoding.EncodeToString(corrIDBytes)
|
||||
rpc.mu.Lock()
|
||||
rpc.pending[corrID] = responseChan
|
||||
rpc.mu.Unlock()
|
||||
|
||||
// Send the request
|
||||
rpc.log.Debug(fmt.Sprintf(" [c>][%s] requesting %s(%s) [%s]", rpc.clientQueue, method, core.B64enc(body), corrID))
|
||||
rpc.log.Debug(fmt.Sprintf(" [c>][%s] requesting %s(%s) [%s]", rpc.clientQueue, method, safeDER(body), corrID))
|
||||
rpc.connection.publish(
|
||||
rpc.serverQueue,
|
||||
corrID,
|
||||
|
|
@ -645,6 +669,7 @@ func (rpc *AmqpRPCCLient) DispatchSync(method string, body []byte) (response []b
|
|||
case jsonResponse := <-responseChan:
|
||||
var rpcResponse rpcResponse
|
||||
err = json.Unmarshal(jsonResponse, &rpcResponse)
|
||||
rpc.log.Debug(fmt.Sprintf(" [c<][%s] response %s: %s [%s]", rpc.clientQueue, method, rpcResponse.debugString(), corrID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"syslog": {
|
||||
"network": "",
|
||||
"server": "",
|
||||
"stdoutlevel": -1
|
||||
"stdoutlevel": 7
|
||||
},
|
||||
|
||||
"amqp": {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
)
|
||||
|
||||
const maxRedirect = 10
|
||||
const whitespaceCutset = "\n\t "
|
||||
|
||||
var validationTimeout = time.Second * 5
|
||||
|
||||
|
|
@ -92,7 +93,7 @@ func verifyValidationJWS(validation *jose.JsonWebSignature, accountKey *jose.Jso
|
|||
return fmt.Errorf("Validation JWS not signed")
|
||||
}
|
||||
|
||||
payload, _, err := validation.Verify(accountKey)
|
||||
payload, err := validation.Verify(accountKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Validation JWS failed to verify: %s", err.Error())
|
||||
}
|
||||
|
|
@ -411,8 +412,10 @@ func (va *ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdenti
|
|||
return challenge, err
|
||||
}
|
||||
|
||||
payload := strings.TrimRight(string(body), whitespaceCutset)
|
||||
|
||||
// Parse and verify JWS
|
||||
parsedJws, err := jose.ParseSigned(string(body))
|
||||
parsedJws, err := jose.ParseSigned(payload)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Validation response failed to parse as JWS: %s", err.Error())
|
||||
va.log.Debug(err.Error())
|
||||
|
|
@ -511,8 +514,10 @@ func (va *ValidationAuthorityImpl) validateHTTP01(identifier core.AcmeIdentifier
|
|||
return challenge, err
|
||||
}
|
||||
|
||||
payload := strings.TrimRight(string(body), whitespaceCutset)
|
||||
|
||||
// Parse body as a key authorization object
|
||||
serverKeyAuthorization, err := core.NewKeyAuthorizationFromString(string(body))
|
||||
serverKeyAuthorization, err := core.NewKeyAuthorizationFromString(payload)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error parsing key authorization file: %s", err.Error())
|
||||
va.log.Debug(err.Error())
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ func createValidation(token string, enableTLS bool) string {
|
|||
"tls": enableTLS,
|
||||
})
|
||||
signer, _ := jose.NewSigner(jose.RS256, &TheKey)
|
||||
obj, _ := signer.Sign(payload, "")
|
||||
obj, _ := signer.Sign(payload)
|
||||
return obj.FullSerialize()
|
||||
}
|
||||
|
||||
|
|
@ -306,6 +306,7 @@ func TestSimpleHttp(t *testing.T) {
|
|||
|
||||
va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, nil, stats, clock.Default())
|
||||
va.DNSResolver = &mocks.DNSResolver{}
|
||||
|
||||
log.Clear()
|
||||
finChall, err := va.validateSimpleHTTP(ident, chall)
|
||||
test.AssertEquals(t, finChall.Status, core.StatusValid)
|
||||
|
|
@ -496,7 +497,7 @@ func TestDvsni(t *testing.T) {
|
|||
"token": chall.Token,
|
||||
})
|
||||
signer, _ := jose.NewSigner(jose.RS256, &TheKey)
|
||||
chall.Validation, _ = signer.Sign(validationPayload, "")
|
||||
chall.Validation, _ = signer.Sign(validationPayload)
|
||||
|
||||
log.Clear()
|
||||
started := time.Now()
|
||||
|
|
@ -588,9 +589,9 @@ func httpSrv(t *testing.T, token string) *httptest.Server {
|
|||
t.Logf("HTTPSRV: Path = %s\n", r.URL.Path)
|
||||
|
||||
keyAuthz, _ := core.NewKeyAuthorization(currentToken, accountKey)
|
||||
t.Logf("HTTPSRV: Key Authz = %s\n", keyAuthz.String())
|
||||
t.Logf("HTTPSRV: Key Authz = '%s%s'\n", keyAuthz.String(), "\\n \\t")
|
||||
|
||||
fmt.Fprint(w, keyAuthz.String())
|
||||
fmt.Fprint(w, keyAuthz.String(), "\n \t")
|
||||
currentToken = defaultToken
|
||||
}
|
||||
})
|
||||
|
|
@ -680,6 +681,7 @@ func TestHttp(t *testing.T) {
|
|||
|
||||
va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, nil, stats, clock.Default())
|
||||
va.DNSResolver = &mocks.DNSResolver{}
|
||||
|
||||
log.Clear()
|
||||
t.Logf("Trying to validate: %+v\n", chall)
|
||||
finChall, err := va.validateHTTP01(ident, chall)
|
||||
|
|
@ -968,7 +970,7 @@ func createChallenge(challengeType string) core.Challenge {
|
|||
"token": chall.Token,
|
||||
})
|
||||
signer, _ := jose.NewSigner(jose.RS256, &TheKey)
|
||||
chall.Validation, _ = signer.Sign(validationPayload, "")
|
||||
chall.Validation, _ = signer.Sign(validationPayload)
|
||||
|
||||
return chall
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ func (wfe *WebFrontEndImpl) verifyPOST(logEvent *requestEvent, request *http.Req
|
|||
return nil, nil, reg, err
|
||||
}
|
||||
|
||||
payload, header, err := parsedJws.Verify(key)
|
||||
payload, err := parsedJws.Verify(key)
|
||||
if err != nil {
|
||||
puberr := core.SignatureValidationError("JWS verification error")
|
||||
wfe.stats.Inc("WFE.Errors.JWSVerificationFailed", 1, 1.0)
|
||||
|
|
@ -440,13 +440,13 @@ func (wfe *WebFrontEndImpl) verifyPOST(logEvent *requestEvent, request *http.Req
|
|||
}
|
||||
|
||||
// Check that the request has a known anti-replay nonce
|
||||
// i.e., Nonce is in protected header and
|
||||
if err != nil || len(header.Nonce) == 0 {
|
||||
nonce := parsedJws.Signatures[0].Header.Nonce
|
||||
if err != nil || len(nonce) == 0 {
|
||||
wfe.stats.Inc("WFE.Errors.JWSMissingNonce", 1, 1.0)
|
||||
logEvent.AddError("JWS is missing an anti-replay nonce")
|
||||
err = core.SignatureValidationError("JWS has no anti-replay nonce")
|
||||
return nil, nil, reg, err
|
||||
} else if !wfe.nonceService.Valid(header.Nonce) {
|
||||
} else if !wfe.nonceService.Valid(nonce) {
|
||||
wfe.stats.Inc("WFE.Errors.JWSInvalidNonce", 1, 1.0)
|
||||
logEvent.AddError("JWS has an invalid anti-replay nonce")
|
||||
err = core.SignatureValidationError(fmt.Sprintf("JWS has invalid anti-replay nonce"))
|
||||
|
|
|
|||
|
|
@ -189,9 +189,8 @@ func signRequest(t *testing.T, req string, nonceService *core.NonceService) stri
|
|||
|
||||
signer, err := jose.NewSigner("RS256", accountKey)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
nonce, err := nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Failed to make nonce")
|
||||
result, err := signer.Sign([]byte(req), nonce)
|
||||
signer.SetNonceSource(nonceService)
|
||||
result, err := signer.Sign([]byte(req))
|
||||
test.AssertNotError(t, err, "Failed to sign req")
|
||||
ret := result.FullSerialize()
|
||||
return ret
|
||||
|
|
@ -752,20 +751,11 @@ func TestNewRegistration(t *testing.T) {
|
|||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
signer, err := jose.NewSigner("RS256", rsaKey)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
nonce, err := wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, err := signer.Sign([]byte("foo"), nonce)
|
||||
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
fooBody, err := signer.Sign([]byte("foo"), nonce)
|
||||
signer.SetNonceSource(wfe.nonceService)
|
||||
fooBody, err := signer.Sign([]byte("foo"))
|
||||
test.AssertNotError(t, err, "Unable to sign")
|
||||
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
wrongAgreementBody, err := signer.Sign(
|
||||
[]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"https://letsencrypt.org/im-bad"}`),
|
||||
nonce)
|
||||
wrongAgreementBody, err := signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"https://letsencrypt.org/im-bad"}`))
|
||||
test.AssertNotError(t, err, "Unable to sign")
|
||||
|
||||
type newRegErrorTest struct {
|
||||
|
|
@ -837,9 +827,7 @@ func TestNewRegistration(t *testing.T) {
|
|||
}
|
||||
|
||||
responseWriter := httptest.NewRecorder()
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"`+agreementURL+`"}`), nonce)
|
||||
result, err := signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"` + agreementURL + `"}`))
|
||||
wfe.NewRegistration(newRequestEvent(), responseWriter,
|
||||
makePostRequest(result.FullSerialize()))
|
||||
|
||||
|
|
@ -868,13 +856,12 @@ func TestNewRegistration(t *testing.T) {
|
|||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
signer, err = jose.NewSigner("RS256", rsaKey)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
signer.SetNonceSource(wfe.nonceService)
|
||||
|
||||
// Reset the body and status code
|
||||
responseWriter = httptest.NewRecorder()
|
||||
// POST, Valid JSON, Key already in use
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"`+agreementURL+`"}`), nonce)
|
||||
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"` + agreementURL + `"}`))
|
||||
|
||||
wfe.NewRegistration(newRequestEvent(), responseWriter,
|
||||
makePostRequest(result.FullSerialize()))
|
||||
|
|
@ -941,9 +928,8 @@ func TestRevokeCertificateCertKey(t *testing.T) {
|
|||
wfe.SA = &mockSANoSuchRegistration{mocks.NewStorageAuthority(fc)}
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
nonce, err := wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, _ := signer.Sign(revokeRequestJSON, nonce)
|
||||
signer.SetNonceSource(wfe.nonceService)
|
||||
result, _ := signer.Sign(revokeRequestJSON)
|
||||
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
|
||||
makePostRequest(result.FullSerialize()))
|
||||
test.AssertEquals(t, responseWriter.Code, 200)
|
||||
|
|
@ -965,9 +951,8 @@ func TestRevokeCertificateAccountKey(t *testing.T) {
|
|||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
accountKeySigner, err := jose.NewSigner("RS256", test1Key)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
nonce, err := wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, _ := accountKeySigner.Sign(revokeRequestJSON, nonce)
|
||||
accountKeySigner.SetNonceSource(wfe.nonceService)
|
||||
result, _ := accountKeySigner.Sign(revokeRequestJSON)
|
||||
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
|
||||
makePostRequest(result.FullSerialize()))
|
||||
test.AssertEquals(t, responseWriter.Code, 200)
|
||||
|
|
@ -977,8 +962,6 @@ func TestRevokeCertificateAccountKey(t *testing.T) {
|
|||
// A revocation request signed by an unauthorized key.
|
||||
func TestRevokeCertificateWrongKey(t *testing.T) {
|
||||
wfe, _ := setupWFE(t)
|
||||
nonce, err := wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
responseWriter := httptest.NewRecorder()
|
||||
test2JWK, err := jose.LoadPrivateKey([]byte(test2KeyPrivatePEM))
|
||||
test.AssertNotError(t, err, "Failed to load key")
|
||||
|
|
@ -986,12 +969,11 @@ func TestRevokeCertificateWrongKey(t *testing.T) {
|
|||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
accountKeySigner2, err := jose.NewSigner("RS256", test2Key)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
accountKeySigner2.SetNonceSource(wfe.nonceService)
|
||||
revokeRequestJSON, err := makeRevokeRequestJSON()
|
||||
test.AssertNotError(t, err, "Unable to create revoke request")
|
||||
|
||||
result, _ := accountKeySigner2.Sign(revokeRequestJSON, nonce)
|
||||
result, _ := accountKeySigner2.Sign(revokeRequestJSON)
|
||||
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
|
||||
makePostRequest(result.FullSerialize()))
|
||||
test.AssertEquals(t, responseWriter.Code, 403)
|
||||
|
|
@ -1031,9 +1013,8 @@ func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
|
|||
wfe.stats, _ = statsd.NewNoopClient()
|
||||
responseWriter := httptest.NewRecorder()
|
||||
responseWriter.Body.Reset()
|
||||
nonce, err := wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, _ := signer.Sign(revokeRequestJSON, nonce)
|
||||
signer.SetNonceSource(wfe.nonceService)
|
||||
result, _ := signer.Sign(revokeRequestJSON)
|
||||
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
|
||||
makePostRequest(result.FullSerialize()))
|
||||
test.AssertEquals(t, responseWriter.Code, 409)
|
||||
|
|
@ -1179,9 +1160,8 @@ func TestRegistration(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
|
||||
// Test POST valid JSON but key is not registered
|
||||
nonce, err := wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, err := signer.Sign([]byte(`{"resource":"reg","agreement":"`+agreementURL+`"}`), nonce)
|
||||
signer.SetNonceSource(wfe.nonceService)
|
||||
result, err := signer.Sign([]byte(`{"resource":"reg","agreement":"` + agreementURL + `"}`))
|
||||
test.AssertNotError(t, err, "Unable to sign")
|
||||
wfe.Registration(newRequestEvent(), responseWriter,
|
||||
makePostRequestWithPath("/2", result.FullSerialize()))
|
||||
|
|
@ -1198,9 +1178,8 @@ func TestRegistration(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
|
||||
// Test POST valid JSON with registration up in the mock (with incorrect agreement URL)
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"https://letsencrypt.org/im-bad"}`), nonce)
|
||||
signer.SetNonceSource(wfe.nonceService)
|
||||
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"https://letsencrypt.org/im-bad"}`))
|
||||
|
||||
// Test POST valid JSON with registration up in the mock
|
||||
wfe.Registration(newRequestEvent(), responseWriter,
|
||||
|
|
@ -1211,9 +1190,7 @@ func TestRegistration(t *testing.T) {
|
|||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST valid JSON with registration up in the mock (with correct agreement URL)
|
||||
nonce, err = wfe.nonceService.Nonce()
|
||||
test.AssertNotError(t, err, "Unable to create nonce")
|
||||
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"`+agreementURL+`"}`), nonce)
|
||||
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"` + agreementURL + `"}`))
|
||||
test.AssertNotError(t, err, "Couldn't sign")
|
||||
wfe.Registration(newRequestEvent(), responseWriter,
|
||||
makePostRequestWithPath("/1", result.FullSerialize()))
|
||||
|
|
|
|||
Loading…
Reference in New Issue