...

Source file src/golang.org/x/crypto/acme/jws_test.go

Documentation: golang.org/x/crypto/acme

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package acme
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/ecdsa"
    10  	"crypto/elliptic"
    11  	"crypto/rsa"
    12  	"crypto/sha256"
    13  	"crypto/x509"
    14  	"encoding/base64"
    15  	"encoding/json"
    16  	"encoding/pem"
    17  	"fmt"
    18  	"io"
    19  	"math/big"
    20  	"testing"
    21  )
    22  
    23  // The following shell command alias is used in the comments
    24  // throughout this file:
    25  // alias b64raw="base64 -w0 | tr -d '=' | tr '/+' '_-'"
    26  
    27  const (
    28  	// Modulus in raw base64:
    29  	// 4xgZ3eRPkwoRvy7qeRUbmMDe0V-xH9eWLdu0iheeLlrmD2mqWXfP9IeSKApbn34
    30  	// g8TuAS9g5zhq8ELQ3kmjr-KV86GAMgI6VAcGlq3QrzpTCf_30Ab7-zawrfRaFON
    31  	// a1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosqEXeaIkVYBEhbh
    32  	// Nu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZfoyFyek380mHg
    33  	// JAumQ_I2fjj98_97mk3ihOY4AgVdCDj1z_GCoZkG5Rq7nbCGyosyKWyDX00Zs-n
    34  	// NqVhoLeIvXC4nnWdJMZ6rogxyQQ
    35  	testKeyPEM = `
    36  -----BEGIN RSA PRIVATE KEY-----
    37  MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
    38  WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
    39  Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq
    40  EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf
    41  oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy
    42  KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV
    43  9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H
    44  r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm
    45  ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP
    46  G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS
    47  zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6
    48  9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s
    49  8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc
    50  7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL
    51  qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ
    52  Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU
    53  RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o
    54  JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd
    55  4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt
    56  jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q
    57  YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73
    58  c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G
    59  N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7
    60  EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
    61  9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx
    62  -----END RSA PRIVATE KEY-----
    63  `
    64  
    65  	// This thumbprint is for the testKey defined above.
    66  	testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
    67  
    68  	// openssl ecparam -name secp256k1 -genkey -noout
    69  	testKeyECPEM = `
    70  -----BEGIN EC PRIVATE KEY-----
    71  MHcCAQEEIK07hGLr0RwyUdYJ8wbIiBS55CjnkMD23DWr+ccnypWLoAoGCCqGSM49
    72  AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
    73  QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
    74  -----END EC PRIVATE KEY-----
    75  `
    76  	// openssl ecparam -name secp384r1 -genkey -noout
    77  	testKeyEC384PEM = `
    78  -----BEGIN EC PRIVATE KEY-----
    79  MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
    80  Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
    81  JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
    82  WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
    83  -----END EC PRIVATE KEY-----
    84  `
    85  	// openssl ecparam -name secp521r1 -genkey -noout
    86  	testKeyEC512PEM = `
    87  -----BEGIN EC PRIVATE KEY-----
    88  MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
    89  KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
    90  7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
    91  FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
    92  GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
    93  -----END EC PRIVATE KEY-----
    94  `
    95  	// 1. openssl ec -in key.pem -noout -text
    96  	// 2. remove first byte, 04 (the header); the rest is X and Y
    97  	// 3. convert each with: echo <val> | xxd -r -p | b64raw
    98  	testKeyECPubX    = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
    99  	testKeyECPubY    = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
   100  	testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
   101  	testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
   102  	testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
   103  	testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
   104  
   105  	// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
   106  	// openssl dgst -binary -sha256 | b64raw
   107  	testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
   108  )
   109  
   110  var (
   111  	testKey      *rsa.PrivateKey
   112  	testKeyEC    *ecdsa.PrivateKey
   113  	testKeyEC384 *ecdsa.PrivateKey
   114  	testKeyEC512 *ecdsa.PrivateKey
   115  )
   116  
   117  func init() {
   118  	testKey = parseRSA(testKeyPEM, "testKeyPEM")
   119  	testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
   120  	testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
   121  	testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
   122  }
   123  
   124  func decodePEM(s, name string) []byte {
   125  	d, _ := pem.Decode([]byte(s))
   126  	if d == nil {
   127  		panic("no block found in " + name)
   128  	}
   129  	return d.Bytes
   130  }
   131  
   132  func parseRSA(s, name string) *rsa.PrivateKey {
   133  	b := decodePEM(s, name)
   134  	k, err := x509.ParsePKCS1PrivateKey(b)
   135  	if err != nil {
   136  		panic(fmt.Sprintf("%s: %v", name, err))
   137  	}
   138  	return k
   139  }
   140  
   141  func parseEC(s, name string) *ecdsa.PrivateKey {
   142  	b := decodePEM(s, name)
   143  	k, err := x509.ParseECPrivateKey(b)
   144  	if err != nil {
   145  		panic(fmt.Sprintf("%s: %v", name, err))
   146  	}
   147  	return k
   148  }
   149  
   150  func TestJWSEncodeJSON(t *testing.T) {
   151  	claims := struct{ Msg string }{"Hello JWS"}
   152  	// JWS signed with testKey and "nonce" as the nonce value
   153  	// JSON-serialized JWS fields are split for easier testing
   154  	const (
   155  		// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce","url":"url"}
   156  		protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
   157  			"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
   158  			"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
   159  			"QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
   160  			"VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
   161  			"NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
   162  			"QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
   163  			"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
   164  			"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
   165  			"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
   166  			"UVEifSwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
   167  		// {"Msg":"Hello JWS"}
   168  		payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
   169  		// printf '<protected>.<payload>' | openssl dgst -binary -sha256 -sign testKey | b64raw
   170  		signature = "YFyl_xz1E7TR-3E1bIuASTr424EgCvBHjt25WUFC2VaDjXYV0Rj_" +
   171  			"Hd3dJ_2IRqBrXDZZ2n4ZeA_4mm3QFwmwyeDwe2sWElhb82lCZ8iX" +
   172  			"uFnjeOmSOjx-nWwPa5ibCXzLq13zZ-OBV1Z4oN_TuailQeRoSfA3" +
   173  			"nO8gG52mv1x2OMQ5MAFtt8jcngBLzts4AyhI6mBJ2w7Yaj3ZCriq" +
   174  			"DWA3GLFvvHdW1Ba9Z01wtGT2CuZI7DUk_6Qj1b3BkBGcoKur5C9i" +
   175  			"bUJtCkABwBMvBQNyD3MmXsrRFRTgvVlyU_yMaucYm7nmzEr_2PaQ" +
   176  			"50rFt_9qOfJ4sfbLtG1Wwae57BQx1g"
   177  	)
   178  
   179  	b, err := jwsEncodeJSON(claims, testKey, noKeyID, "nonce", "url")
   180  	if err != nil {
   181  		t.Fatal(err)
   182  	}
   183  	var jws struct{ Protected, Payload, Signature string }
   184  	if err := json.Unmarshal(b, &jws); err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	if jws.Protected != protected {
   188  		t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
   189  	}
   190  	if jws.Payload != payload {
   191  		t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
   192  	}
   193  	if jws.Signature != signature {
   194  		t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature)
   195  	}
   196  }
   197  
   198  func TestJWSEncodeNoNonce(t *testing.T) {
   199  	kid := KeyID("https://example.org/account/1")
   200  	claims := "RawString"
   201  	const (
   202  		// {"alg":"ES256","kid":"https://example.org/account/1","nonce":"nonce","url":"url"}
   203  		protected = "eyJhbGciOiJFUzI1NiIsImtpZCI6Imh0dHBzOi8vZXhhbXBsZS5vcmcvYWNjb3VudC8xIiwidXJsIjoidXJsIn0"
   204  		// "Raw String"
   205  		payload = "RawString"
   206  	)
   207  
   208  	b, err := jwsEncodeJSON(claims, testKeyEC, kid, "", "url")
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  	var jws struct{ Protected, Payload, Signature string }
   213  	if err := json.Unmarshal(b, &jws); err != nil {
   214  		t.Fatal(err)
   215  	}
   216  	if jws.Protected != protected {
   217  		t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
   218  	}
   219  	if jws.Payload != payload {
   220  		t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
   221  	}
   222  
   223  	sig, err := base64.RawURLEncoding.DecodeString(jws.Signature)
   224  	if err != nil {
   225  		t.Fatalf("jws.Signature: %v", err)
   226  	}
   227  	r, s := big.NewInt(0), big.NewInt(0)
   228  	r.SetBytes(sig[:len(sig)/2])
   229  	s.SetBytes(sig[len(sig)/2:])
   230  	h := sha256.Sum256([]byte(protected + "." + payload))
   231  	if !ecdsa.Verify(testKeyEC.Public().(*ecdsa.PublicKey), h[:], r, s) {
   232  		t.Error("invalid signature")
   233  	}
   234  }
   235  
   236  func TestJWSEncodeKID(t *testing.T) {
   237  	kid := KeyID("https://example.org/account/1")
   238  	claims := struct{ Msg string }{"Hello JWS"}
   239  	// JWS signed with testKeyEC
   240  	const (
   241  		// {"alg":"ES256","kid":"https://example.org/account/1","nonce":"nonce","url":"url"}
   242  		protected = "eyJhbGciOiJFUzI1NiIsImtpZCI6Imh0dHBzOi8vZXhhbXBsZS5" +
   243  			"vcmcvYWNjb3VudC8xIiwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
   244  		// {"Msg":"Hello JWS"}
   245  		payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
   246  	)
   247  
   248  	b, err := jwsEncodeJSON(claims, testKeyEC, kid, "nonce", "url")
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	var jws struct{ Protected, Payload, Signature string }
   253  	if err := json.Unmarshal(b, &jws); err != nil {
   254  		t.Fatal(err)
   255  	}
   256  	if jws.Protected != protected {
   257  		t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
   258  	}
   259  	if jws.Payload != payload {
   260  		t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
   261  	}
   262  
   263  	sig, err := base64.RawURLEncoding.DecodeString(jws.Signature)
   264  	if err != nil {
   265  		t.Fatalf("jws.Signature: %v", err)
   266  	}
   267  	r, s := big.NewInt(0), big.NewInt(0)
   268  	r.SetBytes(sig[:len(sig)/2])
   269  	s.SetBytes(sig[len(sig)/2:])
   270  	h := sha256.Sum256([]byte(protected + "." + payload))
   271  	if !ecdsa.Verify(testKeyEC.Public().(*ecdsa.PublicKey), h[:], r, s) {
   272  		t.Error("invalid signature")
   273  	}
   274  }
   275  
   276  func TestJWSEncodeJSONEC(t *testing.T) {
   277  	tt := []struct {
   278  		key      *ecdsa.PrivateKey
   279  		x, y     string
   280  		alg, crv string
   281  	}{
   282  		{testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
   283  		{testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
   284  		{testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
   285  	}
   286  	for i, test := range tt {
   287  		claims := struct{ Msg string }{"Hello JWS"}
   288  		b, err := jwsEncodeJSON(claims, test.key, noKeyID, "nonce", "url")
   289  		if err != nil {
   290  			t.Errorf("%d: %v", i, err)
   291  			continue
   292  		}
   293  		var jws struct{ Protected, Payload, Signature string }
   294  		if err := json.Unmarshal(b, &jws); err != nil {
   295  			t.Errorf("%d: %v", i, err)
   296  			continue
   297  		}
   298  
   299  		b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
   300  		if err != nil {
   301  			t.Errorf("%d: jws.Protected: %v", i, err)
   302  		}
   303  		var head struct {
   304  			Alg   string
   305  			Nonce string
   306  			URL   string `json:"url"`
   307  			KID   string `json:"kid"`
   308  			JWK   struct {
   309  				Crv string
   310  				Kty string
   311  				X   string
   312  				Y   string
   313  			} `json:"jwk"`
   314  		}
   315  		if err := json.Unmarshal(b, &head); err != nil {
   316  			t.Errorf("%d: jws.Protected: %v", i, err)
   317  		}
   318  		if head.Alg != test.alg {
   319  			t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
   320  		}
   321  		if head.Nonce != "nonce" {
   322  			t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
   323  		}
   324  		if head.URL != "url" {
   325  			t.Errorf("%d: head.URL = %q; want 'url'", i, head.URL)
   326  		}
   327  		if head.KID != "" {
   328  			// We used noKeyID in jwsEncodeJSON: expect no kid value.
   329  			t.Errorf("%d: head.KID = %q; want empty", i, head.KID)
   330  		}
   331  		if head.JWK.Crv != test.crv {
   332  			t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
   333  		}
   334  		if head.JWK.Kty != "EC" {
   335  			t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
   336  		}
   337  		if head.JWK.X != test.x {
   338  			t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
   339  		}
   340  		if head.JWK.Y != test.y {
   341  			t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
   342  		}
   343  	}
   344  }
   345  
   346  type customTestSigner struct {
   347  	sig []byte
   348  	pub crypto.PublicKey
   349  }
   350  
   351  func (s *customTestSigner) Public() crypto.PublicKey { return s.pub }
   352  func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) {
   353  	return s.sig, nil
   354  }
   355  
   356  func TestJWSEncodeJSONCustom(t *testing.T) {
   357  	claims := struct{ Msg string }{"hello"}
   358  	const (
   359  		// printf '{"Msg":"hello"}' | b64raw
   360  		payload = "eyJNc2ciOiJoZWxsbyJ9"
   361  		// printf 'testsig' | b64raw
   362  		testsig = "dGVzdHNpZw"
   363  
   364  		// the example P256 curve point from https://tools.ietf.org/html/rfc7515#appendix-A.3.1
   365  		// encoded as ASN.1…
   366  		es256stdsig = "MEUCIA7RIVN5Y2xIPC9/FVgH1AKjsigDOvl8fheBmsMWnqZlAiEA" +
   367  			"xQoH04w8cOXY8S2vCEpUgKZlkMXyk1Cajz9/ioOjVNU"
   368  		// …and RFC7518 (https://tools.ietf.org/html/rfc7518#section-3.4)
   369  		es256jwsig = "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw" +
   370  			"5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
   371  
   372  		// printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":<testKeyECPubY>,"y":<testKeyECPubY>},"nonce":"nonce","url":"url"}' | b64raw
   373  		es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0" +
   374  			"eSI6IkVDIiwieCI6IjVsaEV1ZzV4SzR4QkRaMm5BYmF4THRhTGl2" +
   375  			"ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFHa3Yw" +
   376  			"VGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6" +
   377  			"Im5vbmNlIiwidXJsIjoidXJsIn0"
   378  
   379  		// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce","url":"url"}
   380  		rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
   381  			"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
   382  			"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
   383  			"QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
   384  			"VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
   385  			"NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
   386  			"QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
   387  			"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
   388  			"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
   389  			"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
   390  			"UVEifSwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
   391  	)
   392  
   393  	tt := []struct {
   394  		alg, phead    string
   395  		pub           crypto.PublicKey
   396  		stdsig, jwsig string
   397  	}{
   398  		{"ES256", es256phead, testKeyEC.Public(), es256stdsig, es256jwsig},
   399  		{"RS256", rs256phead, testKey.Public(), testsig, testsig},
   400  	}
   401  	for _, tc := range tt {
   402  		tc := tc
   403  		t.Run(tc.alg, func(t *testing.T) {
   404  			stdsig, err := base64.RawStdEncoding.DecodeString(tc.stdsig)
   405  			if err != nil {
   406  				t.Errorf("couldn't decode test vector: %v", err)
   407  			}
   408  			signer := &customTestSigner{
   409  				sig: stdsig,
   410  				pub: tc.pub,
   411  			}
   412  
   413  			b, err := jwsEncodeJSON(claims, signer, noKeyID, "nonce", "url")
   414  			if err != nil {
   415  				t.Fatal(err)
   416  			}
   417  			var j jsonWebSignature
   418  			if err := json.Unmarshal(b, &j); err != nil {
   419  				t.Fatal(err)
   420  			}
   421  			if j.Protected != tc.phead {
   422  				t.Errorf("j.Protected = %q\nwant %q", j.Protected, tc.phead)
   423  			}
   424  			if j.Payload != payload {
   425  				t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload)
   426  			}
   427  			if j.Sig != tc.jwsig {
   428  				t.Errorf("j.Sig = %q\nwant %q", j.Sig, tc.jwsig)
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  func TestJWSWithMAC(t *testing.T) {
   435  	// Example from RFC 7520 Section 4.4.3.
   436  	// https://tools.ietf.org/html/rfc7520#section-4.4.3
   437  	b64Key := "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg"
   438  	rawPayload := []byte("It\xe2\x80\x99s a dangerous business, Frodo, going out your " +
   439  		"door. You step onto the road, and if you don't keep your feet, " +
   440  		"there\xe2\x80\x99s no knowing where you might be swept off " +
   441  		"to.")
   442  	protected := "eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LW" +
   443  		"VlZjMxNGJjNzAzNyJ9"
   444  	payload := "SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywg" +
   445  		"Z29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9h" +
   446  		"ZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXi" +
   447  		"gJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9m" +
   448  		"ZiB0by4"
   449  	sig := "s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0"
   450  
   451  	key, err := base64.RawURLEncoding.DecodeString(b64Key)
   452  	if err != nil {
   453  		t.Fatalf("unable to decode key: %q", b64Key)
   454  	}
   455  	got, err := jwsWithMAC(key, "018c0ae5-4d9b-471b-bfd6-eef314bc7037", "", rawPayload)
   456  	if err != nil {
   457  		t.Fatalf("jwsWithMAC() = %q", err)
   458  	}
   459  	if got.Protected != protected {
   460  		t.Errorf("got.Protected = %q\nwant %q", got.Protected, protected)
   461  	}
   462  	if got.Payload != payload {
   463  		t.Errorf("got.Payload = %q\nwant %q", got.Payload, payload)
   464  	}
   465  	if got.Sig != sig {
   466  		t.Errorf("got.Signature = %q\nwant %q", got.Sig, sig)
   467  	}
   468  }
   469  
   470  func TestJWSWithMACError(t *testing.T) {
   471  	p := "{}"
   472  	if _, err := jwsWithMAC(nil, "", "", []byte(p)); err == nil {
   473  		t.Errorf("jwsWithMAC(nil, ...) = success; want err")
   474  	}
   475  }
   476  
   477  func TestJWKThumbprintRSA(t *testing.T) {
   478  	// Key example from RFC 7638
   479  	const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
   480  		"VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" +
   481  		"4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" +
   482  		"W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" +
   483  		"1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" +
   484  		"aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
   485  	const base64E = "AQAB"
   486  	const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
   487  
   488  	b, err := base64.RawURLEncoding.DecodeString(base64N)
   489  	if err != nil {
   490  		t.Fatalf("Error parsing example key N: %v", err)
   491  	}
   492  	n := new(big.Int).SetBytes(b)
   493  
   494  	b, err = base64.RawURLEncoding.DecodeString(base64E)
   495  	if err != nil {
   496  		t.Fatalf("Error parsing example key E: %v", err)
   497  	}
   498  	e := new(big.Int).SetBytes(b)
   499  
   500  	pub := &rsa.PublicKey{N: n, E: int(e.Uint64())}
   501  	th, err := JWKThumbprint(pub)
   502  	if err != nil {
   503  		t.Error(err)
   504  	}
   505  	if th != expected {
   506  		t.Errorf("thumbprint = %q; want %q", th, expected)
   507  	}
   508  }
   509  
   510  func TestJWKThumbprintEC(t *testing.T) {
   511  	// Key example from RFC 7520
   512  	// expected was computed with
   513  	// printf '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \
   514  	// openssl dgst -binary -sha256 | b64raw
   515  	const (
   516  		base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" +
   517  			"KqjqvjyekWF-7ytDyRXYgCF5cj0Kt"
   518  		base64Y = "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUda" +
   519  			"QkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
   520  		expected = "dHri3SADZkrush5HU_50AoRhcKFryN-PI6jPBtPL55M"
   521  	)
   522  
   523  	b, err := base64.RawURLEncoding.DecodeString(base64X)
   524  	if err != nil {
   525  		t.Fatalf("Error parsing example key X: %v", err)
   526  	}
   527  	x := new(big.Int).SetBytes(b)
   528  
   529  	b, err = base64.RawURLEncoding.DecodeString(base64Y)
   530  	if err != nil {
   531  		t.Fatalf("Error parsing example key Y: %v", err)
   532  	}
   533  	y := new(big.Int).SetBytes(b)
   534  
   535  	pub := &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y}
   536  	th, err := JWKThumbprint(pub)
   537  	if err != nil {
   538  		t.Error(err)
   539  	}
   540  	if th != expected {
   541  		t.Errorf("thumbprint = %q; want %q", th, expected)
   542  	}
   543  }
   544  
   545  func TestJWKThumbprintErrUnsupportedKey(t *testing.T) {
   546  	_, err := JWKThumbprint(struct{}{})
   547  	if err != ErrUnsupportedKey {
   548  		t.Errorf("err = %q; want %q", err, ErrUnsupportedKey)
   549  	}
   550  }
   551  

View as plain text