...

Source file src/gopkg.in/square/go-jose.v2/jwk_test.go

Documentation: gopkg.in/square/go-jose.v2

     1  /*-
     2   * Copyright 2014 Square Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package jose
    18  
    19  import (
    20  	"bytes"
    21  	"crypto"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"crypto/rsa"
    25  	"crypto/sha1"
    26  	"crypto/sha256"
    27  	"crypto/x509"
    28  	"encoding/hex"
    29  	"math/big"
    30  	"reflect"
    31  	"strings"
    32  	"testing"
    33  
    34  	"github.com/google/go-cmp/cmp"
    35  	"github.com/stretchr/testify/assert"
    36  	"github.com/stretchr/testify/require"
    37  
    38  	"golang.org/x/crypto/ed25519"
    39  
    40  	"gopkg.in/square/go-jose.v2/json"
    41  )
    42  
    43  // Test chain of two X.509 certificates
    44  var testCertificates, _ = x509.ParseCertificates(fromBase64Bytes(`
    45  MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJ
    46  BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4G
    47  A1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYx
    48  MDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNV
    49  BAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUw
    50  EwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
    51  ggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKd
    52  sR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafE
    53  gJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieec
    54  w2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a9
    55  4rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+j
    56  HDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGj
    57  TzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAj
    58  hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcN
    59  AQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05
    60  kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7
    61  LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloS
    62  aa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx
    63  8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObi
    64  qdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIUwggNT
    65  MIICO6ADAgECAgkAqD4tCWKt9/AwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UE
    66  BhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQL
    67  EwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwHhcNMTYwNjEwMjIx
    68  NDExWhcNMjMwNDE1MjIxNDExWjBVMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
    69  Q0ExEDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1wbGUxFTATBgNV
    70  BAMTDGV4YW1wbGUtcm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
    71  ggEBAMo4ShKI2MxDz/NQVxBbz0tbD5R5NcobA0NKkaPKLyMEpnWVY9ucyauM
    72  joNn1F568cfOoF0pm3700U8UTPt2MMxEHIi4mFG/OF8UF+Voh1J42Tb42lRo
    73  W5RRR3ogh4+7QB1G94nxkYddHAJ4QMhUJlLigFg8c6Ff/MxYODy9I7ilLFOM
    74  Zzsjx8fFpRKRXNQFt471P/V4WTSba7GzdTOJRyTZf/xipF36n8RoEQPvyde8
    75  pEAsCC4oDOrEiCTdxw8rRJVAU0Wr55XX+qjxyi55C6oykIC/BWR+lUqGd7IL
    76  Y2Uyt/OVxllt8b+KuVKNCfn4TFlfgizLWkJRs6JV9KuwJ20CAwEAAaMmMCQw
    77  DgYDVR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcN
    78  AQELBQADggEBAIsQlTrm9NT6gts0cs4JHp8AutuMrvGyLpIUOlJcEybvgxaz
    79  LebIMGZek5w3yEJiCyCK9RdNDP3Kdc/+nM6PhvzfPOVo58+0tMCYyEpZVXhD
    80  zmasNDP4fMbiUpczvx5OwPw/KuhwD+1ITuZUQnQlqXgTYoj9n39+qlgUsHos
    81  WXHmfzd6Fcz96ADSXg54IL2cEoJ41Q3ewhA7zmWWPLMAl21aex2haiAmzqqN
    82  xXyfZTnGNnE3lkV1yVguOrqDZyMRdcxDFvxvtmEeMtYV2Mc/zlS9ccrcOkrc
    83  mZSDxthLu3UMl98NA2NrCGWwzJwpk36vQ0PRSbibsCMarFspP8zbIoU=`))
    84  
    85  func TestCurveSize(t *testing.T) {
    86  	size256 := curveSize(elliptic.P256())
    87  	size384 := curveSize(elliptic.P384())
    88  	size521 := curveSize(elliptic.P521())
    89  	if size256 != 32 {
    90  		t.Error("P-256 have 32 bytes")
    91  	}
    92  	if size384 != 48 {
    93  		t.Error("P-384 have 48 bytes")
    94  	}
    95  	if size521 != 66 {
    96  		t.Error("P-521 have 66 bytes")
    97  	}
    98  }
    99  
   100  func TestRoundtripRsaPrivate(t *testing.T) {
   101  	jwk, err := fromRsaPrivateKey(rsaTestKey)
   102  	if err != nil {
   103  		t.Error("problem constructing JWK from rsa key", err)
   104  	}
   105  
   106  	rsa2, err := jwk.rsaPrivateKey()
   107  	if err != nil {
   108  		t.Error("problem converting RSA private -> JWK", err)
   109  	}
   110  
   111  	if rsa2.N.Cmp(rsaTestKey.N) != 0 {
   112  		t.Error("RSA private N mismatch")
   113  	}
   114  	if rsa2.E != rsaTestKey.E {
   115  		t.Error("RSA private E mismatch")
   116  	}
   117  	if rsa2.D.Cmp(rsaTestKey.D) != 0 {
   118  		t.Error("RSA private D mismatch")
   119  	}
   120  	if len(rsa2.Primes) != 2 {
   121  		t.Error("RSA private roundtrip expected two primes")
   122  	}
   123  	if rsa2.Primes[0].Cmp(rsaTestKey.Primes[0]) != 0 {
   124  		t.Error("RSA private P mismatch")
   125  	}
   126  	if rsa2.Primes[1].Cmp(rsaTestKey.Primes[1]) != 0 {
   127  		t.Error("RSA private Q mismatch")
   128  	}
   129  }
   130  
   131  func TestRoundtripRsaPrivatePrecomputed(t *testing.T) {
   132  	// Isolate a shallow copy of the rsaTestKey to avoid polluting it with Precompute
   133  	localKey := &(*rsaTestKey)
   134  	localKey.Precompute()
   135  
   136  	jwk, err := fromRsaPrivateKey(localKey)
   137  	if err != nil {
   138  		t.Error("problem constructing JWK from rsa key", err)
   139  	}
   140  
   141  	rsa2, err := jwk.rsaPrivateKey()
   142  	if err != nil {
   143  		t.Error("problem converting RSA private -> JWK", err)
   144  	}
   145  
   146  	if rsa2.Precomputed.Dp == nil {
   147  		t.Error("RSA private Dp nil")
   148  	}
   149  	if rsa2.Precomputed.Dq == nil {
   150  		t.Error("RSA private Dq nil")
   151  	}
   152  	if rsa2.Precomputed.Qinv == nil {
   153  		t.Error("RSA private Qinv nil")
   154  	}
   155  
   156  	if rsa2.Precomputed.Dp.Cmp(localKey.Precomputed.Dp) != 0 {
   157  		t.Error("RSA private Dp mismatch")
   158  	}
   159  	if rsa2.Precomputed.Dq.Cmp(localKey.Precomputed.Dq) != 0 {
   160  		t.Error("RSA private Dq mismatch")
   161  	}
   162  	if rsa2.Precomputed.Qinv.Cmp(localKey.Precomputed.Qinv) != 0 {
   163  		t.Error("RSA private Qinv mismatch")
   164  	}
   165  }
   166  
   167  func TestRsaPrivateInsufficientPrimes(t *testing.T) {
   168  	brokenRsaPrivateKey := rsa.PrivateKey{
   169  		PublicKey: rsa.PublicKey{
   170  			N: rsaTestKey.N,
   171  			E: rsaTestKey.E,
   172  		},
   173  		D:      rsaTestKey.D,
   174  		Primes: []*big.Int{rsaTestKey.Primes[0]},
   175  	}
   176  
   177  	_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
   178  	if err != ErrUnsupportedKeyType {
   179  		t.Error("expected unsupported key type error, got", err)
   180  	}
   181  }
   182  
   183  func TestRsaPrivateExcessPrimes(t *testing.T) {
   184  	brokenRsaPrivateKey := rsa.PrivateKey{
   185  		PublicKey: rsa.PublicKey{
   186  			N: rsaTestKey.N,
   187  			E: rsaTestKey.E,
   188  		},
   189  		D: rsaTestKey.D,
   190  		Primes: []*big.Int{
   191  			rsaTestKey.Primes[0],
   192  			rsaTestKey.Primes[1],
   193  			big.NewInt(3),
   194  		},
   195  	}
   196  
   197  	_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
   198  	if err != ErrUnsupportedKeyType {
   199  		t.Error("expected unsupported key type error, got", err)
   200  	}
   201  }
   202  
   203  func TestRoundtripEcPublic(t *testing.T) {
   204  	for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
   205  		jwk, err := fromEcPublicKey(&ecTestKey.PublicKey)
   206  
   207  		ec2, err := jwk.ecPublicKey()
   208  		if err != nil {
   209  			t.Error("problem converting ECDSA private -> JWK", i, err)
   210  		}
   211  
   212  		if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
   213  			t.Error("ECDSA private curve mismatch", i)
   214  		}
   215  		if ec2.X.Cmp(ecTestKey.X) != 0 {
   216  			t.Error("ECDSA X mismatch", i)
   217  		}
   218  		if ec2.Y.Cmp(ecTestKey.Y) != 0 {
   219  			t.Error("ECDSA Y mismatch", i)
   220  		}
   221  	}
   222  }
   223  
   224  func TestRoundtripEcPrivate(t *testing.T) {
   225  	for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
   226  		jwk, err := fromEcPrivateKey(ecTestKey)
   227  
   228  		ec2, err := jwk.ecPrivateKey()
   229  		if err != nil {
   230  			t.Fatalf("problem converting ECDSA private -> JWK for %#v: %s", ecTestKey, err)
   231  		}
   232  
   233  		if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
   234  			t.Error("ECDSA private curve mismatch", i)
   235  		}
   236  		if ec2.X.Cmp(ecTestKey.X) != 0 {
   237  			t.Error("ECDSA X mismatch", i)
   238  		}
   239  		if ec2.Y.Cmp(ecTestKey.Y) != 0 {
   240  			t.Error("ECDSA Y mismatch", i)
   241  		}
   242  		if ec2.D.Cmp(ecTestKey.D) != 0 {
   243  			t.Error("ECDSA D mismatch", i)
   244  		}
   245  	}
   246  }
   247  
   248  func TestRoundtripX509(t *testing.T) {
   249  	x5tSHA1 := sha1.Sum(testCertificates[0].Raw)
   250  	x5tSHA256 := sha256.Sum256(testCertificates[0].Raw)
   251  
   252  	cases := []struct {
   253  		name string
   254  		jwk  JSONWebKey
   255  	}{
   256  		{
   257  			name: "all fields",
   258  			jwk: JSONWebKey{
   259  				Key:                         testCertificates[0].PublicKey,
   260  				KeyID:                       "bar",
   261  				Algorithm:                   "foo",
   262  				Certificates:                testCertificates,
   263  				CertificateThumbprintSHA1:   x5tSHA1[:],
   264  				CertificateThumbprintSHA256: x5tSHA256[:],
   265  			},
   266  		},
   267  		{
   268  			name: "no optional x5ts",
   269  			jwk: JSONWebKey{
   270  				Key:          testCertificates[0].PublicKey,
   271  				KeyID:        "bar",
   272  				Algorithm:    "foo",
   273  				Certificates: testCertificates,
   274  			},
   275  		},
   276  		{
   277  			name: "no x5t",
   278  			jwk: JSONWebKey{
   279  				Key:                         testCertificates[0].PublicKey,
   280  				KeyID:                       "bar",
   281  				Algorithm:                   "foo",
   282  				Certificates:                testCertificates,
   283  				CertificateThumbprintSHA256: x5tSHA256[:],
   284  			},
   285  		},
   286  		{
   287  			name: "no x5t#S256",
   288  			jwk: JSONWebKey{
   289  				Key:                       testCertificates[0].PublicKey,
   290  				KeyID:                     "bar",
   291  				Algorithm:                 "foo",
   292  				Certificates:              testCertificates,
   293  				CertificateThumbprintSHA1: x5tSHA1[:],
   294  			},
   295  		},
   296  	}
   297  
   298  	for _, c := range cases {
   299  		t.Run(c.name, func(t *testing.T) {
   300  			jsonbar, err := c.jwk.MarshalJSON()
   301  			require.NoError(t, err)
   302  
   303  			var jwk2 JSONWebKey
   304  			err = jwk2.UnmarshalJSON(jsonbar)
   305  			require.NoError(t, err)
   306  
   307  			if !reflect.DeepEqual(testCertificates, jwk2.Certificates) {
   308  				t.Error("Certificates not equal", c.jwk.Certificates, jwk2.Certificates)
   309  			}
   310  
   311  			jsonbar2, err := jwk2.MarshalJSON()
   312  			require.NoError(t, err)
   313  
   314  			require.Empty(t, cmp.Diff(jsonbar, jsonbar2))
   315  			if !bytes.Equal(jsonbar, jsonbar2) {
   316  				t.Error("roundtrip should not lose information")
   317  			}
   318  		})
   319  	}
   320  }
   321  
   322  func TestRoundtripX509Hex(t *testing.T) {
   323  	var hexJWK = `{
   324     "kty":"RSA",
   325     "kid":"bar",
   326     "alg":"foo",
   327     "n":"u7LUr30Mhrh8N79-H4rKiHQ123q6xaBZPYbf1nV4GM19rizSnbEfyebG1kpfCv-XY6c499XiM6lOvcPL-0goTOcfW6Lg7AAR895GbnMeXEmnxICaI8rAZHK6t1WPmiWp82y_qhK2F_pYUaT3GSuiTFiMGq_GNwdpWuMlsInnnMNv1nxFbxtDPwzmCp0fEBxbH5d1EtXZwTPOHMyj8rfa-NIA5Nl4h_5RrbOWveKwBr26_CDAratJgOWh9xcd5g0ot_uDGcMoAgB6xeTuYklfaxCPptvu49kvoxw1J71fp6nKW_ZuhDRAp2F_BQ9inKpTo05sPLJg8tPTdjaeouOuJQ",
   328     "e":"AQAB",
   329     "x5c":[
   330        "MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=",
   331        "MIIDUzCCAjugAwIBAgIJAKg+LQlirffwMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1yb290MB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQW89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDIVCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3UziUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8coueQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSrsCdtAgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQCLEJU65vTU+oLbNHLOCR6fALrbjK7xsi6SFDpSXBMm74MWsy3myDBmXpOcN8hCYgsgivUXTQz9ynXP/pzOj4b83zzlaOfPtLTAmMhKWVV4Q85mrDQz+HzG4lKXM78eTsD8PyrocA/tSE7mVEJ0Jal4E2KI/Z9/fqpYFLB6LFlx5n83ehXM/egA0l4OeCC9nBKCeNUN3sIQO85lljyzAJdtWnsdoWogJs6qjcV8n2U5xjZxN5ZFdclYLjq6g2cjEXXMQxb8b7ZhHjLWFdjHP85UvXHK3DpK3JmUg8bYS7t1DJffDQNjawhlsMycKZN+r0ND0Um4m7AjGqxbKT/M2yKF"
   332  	],
   333  	"x5t": "MDYxMjU0ZmRmNzIwZjJjMGU0YmQzZjMzMzlhMmZlNTM1MGExNWRlMQ",
   334  	"x5t#S256": "MjAzMjRhNGI5MmYxMjI2OGVmOWFlMDI1ZmQ1Yzc5ZDE1OGZmNzQ1NzQwMDkyMTk2ZTgzNTNjMDAzMTUxNzUxMQ"
   335  }`
   336  
   337  	// json output
   338  	var output = `{
   339  	"kty":"RSA",
   340  	"kid":"bar",
   341  	"alg":"foo",
   342  	"n":"u7LUr30Mhrh8N79-H4rKiHQ123q6xaBZPYbf1nV4GM19rizSnbEfyebG1kpfCv-XY6c499XiM6lOvcPL-0goTOcfW6Lg7AAR895GbnMeXEmnxICaI8rAZHK6t1WPmiWp82y_qhK2F_pYUaT3GSuiTFiMGq_GNwdpWuMlsInnnMNv1nxFbxtDPwzmCp0fEBxbH5d1EtXZwTPOHMyj8rfa-NIA5Nl4h_5RrbOWveKwBr26_CDAratJgOWh9xcd5g0ot_uDGcMoAgB6xeTuYklfaxCPptvu49kvoxw1J71fp6nKW_ZuhDRAp2F_BQ9inKpTo05sPLJg8tPTdjaeouOuJQ",
   343  	"e":"AQAB",
   344  	"x5c":[
   345  		"MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=",
   346  		"MIIDUzCCAjugAwIBAgIJAKg+LQlirffwMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1yb290MB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQW89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDIVCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3UziUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8coueQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSrsCdtAgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQCLEJU65vTU+oLbNHLOCR6fALrbjK7xsi6SFDpSXBMm74MWsy3myDBmXpOcN8hCYgsgivUXTQz9ynXP/pzOj4b83zzlaOfPtLTAmMhKWVV4Q85mrDQz+HzG4lKXM78eTsD8PyrocA/tSE7mVEJ0Jal4E2KI/Z9/fqpYFLB6LFlx5n83ehXM/egA0l4OeCC9nBKCeNUN3sIQO85lljyzAJdtWnsdoWogJs6qjcV8n2U5xjZxN5ZFdclYLjq6g2cjEXXMQxb8b7ZhHjLWFdjHP85UvXHK3DpK3JmUg8bYS7t1DJffDQNjawhlsMycKZN+r0ND0Um4m7AjGqxbKT/M2yKF"
   347  	],
   348  	"x5t":"BhJU_fcg8sDkvT8zOaL-U1ChXeE",
   349  	"x5t#S256":"IDJKS5LxImjvmuAl_Vx50Vj_dFdACSGW6DU8ADFRdRE"
   350  	}`
   351  
   352  	var jwk2 JSONWebKey
   353  	err := jwk2.UnmarshalJSON([]byte(hexJWK))
   354  	require.NoError(t, err)
   355  
   356  	js, err := jwk2.MarshalJSON()
   357  	require.NoError(t, err)
   358  
   359  	var j1, j2 map[string]interface{}
   360  	require.NoError(t, json.Unmarshal(js, &j1))
   361  	require.NoError(t, json.Unmarshal([]byte(output), &j2))
   362  	require.Empty(t, cmp.Diff(j1, j2))
   363  }
   364  
   365  func TestInvalidThumbprintsX509(t *testing.T) {
   366  	// Too short
   367  	jwk := JSONWebKey{
   368  		Key:                         rsaTestKey,
   369  		KeyID:                       "bar",
   370  		Algorithm:                   "foo",
   371  		Certificates:                testCertificates,
   372  		CertificateThumbprintSHA1:   []byte{0x01}, // invalid length
   373  		CertificateThumbprintSHA256: []byte{0x02}, // invalid length
   374  	}
   375  
   376  	_, err := jwk.MarshalJSON()
   377  	if err == nil {
   378  		t.Error("should not marshal JWK with too short thumbprints")
   379  	}
   380  
   381  	// Mismatched (leaf has different sum)
   382  	sha1sum := sha1.Sum(nil)
   383  	jwk.CertificateThumbprintSHA1 = sha1sum[:]
   384  	sha256sum := sha256.Sum256(nil)
   385  	jwk.CertificateThumbprintSHA256 = sha256sum[:]
   386  
   387  	_, err = jwk.MarshalJSON()
   388  	if err == nil {
   389  		t.Error("should not marshal JWK with mismatched thumbprints")
   390  	}
   391  
   392  	// Too short
   393  	shortThumbprints := []byte(`{
   394    "kty": "RSA",
   395    "kid": "bar",
   396    "alg": "foo",
   397    "n": "wN3v274Fr7grvZdXirEGkHlhYKh72gP-46MxQilMgANi6EaX2m0mYiMC60X1UmOhQNoVW0ItthMME-CGh7haA_Jeou_L6-EVOz-7lGu_J06VRl-mgkQZO0sYSkRY8Rsu7TW-pgnWWwZjSdgxN2gq7DvjjC4RLroV94Lgrb2Qwx6J5bZNOfj3pHmEWZ_eRFEH73Ct5RxwUKtNKx_XAmodZn9oFXBlN7F2Js-4DO-8UgbS7ALkTmhDzClT1GPfdLMusmXw4BXyV72vBOWrbUTdwk4pG8ahPQ0cGQ1ubaAmro_k3Bxg06voWPhXx7ALrpzmZCzr6YY-c5Y5rku4qXh-HQ",
   398    "e": "AQAB",
   399    "d": "RRM3xMvZ3YVopQ5_G_0rDLNsXOH6-apUr9LS4Y9JBtAvrGEcIe7VwHApq3ny0v870a5J19Vr6boIqVXQ2Or90kwL-O9JacHDiOTamd29KKbMb9fyGtWo88OBf5fbAv9pXyvQjEcZrqArD1eOyPlV5iXM6XfWT5X2KB-HuLIcFsVJSEb0yw943dEhZKkv2fySlVtKEhji2CfkMWP438G8auxwFPNIXmuvA1xvcAepOiI9I1Wy17txLOQg8MYBl98F7mxPUMpL3jm8-CSuxpknucFuFIrqIsbGmukSNp14APcu7bN0cJW5uVW-XtGbuioJkPjU2YJgfhIeMI8kuny5QQ",
   400    "p": "yRNzbsreZK9MqJgbVsbl7SX2MyyJW_JnFKGdyrXzMqCtzRS7XJ9L3SwdDG_ERgSCkT9PP2dax9fS7RghHNJIU_NlPnJqzBPvPyzbjho7hcGYGDU2UO8E3SBP1WKm1SnlYhm1uHwrHudAO0D5jhVYQfRwem-zX3QibrsxEyxSELM",
   401    "q": "9Yx0zzrhSxdE8ubryZfOyOw6cSbUdyCMgY3IFmEdb_UDZOQNMDCFj2RS1g6yFGKuaFqnL9ZRnmprikf20w-mu-LtLU_l0eK4U7pbAoB--pxFP_O6Yk3ZBu_YJ3FpimyX1v4OVZT-JOU_caKiTrPnlw3P7KbEc9iu_bOc8dE-_e8",
   402    "dp": "GwiFbXDS44B58vS4QDtvcCm5Zvnm4bi-SRTNbRJ3Rug5Vagi5Hn6LhsfMKvaHHvAvhxf4CtaFiIbFos28HQJC1he1T12xEct1DWIsxstw3bapu6IhesMoVoVwZ-IxIHkeALy3oG7HmWCyjSbGJIgEoX1lVBtMjkf4_lAyM4dnmc",
   403    "dq": "XYtXyMbOo3PG8Z6lfxRVU9gi346CbKu6u3RPIK94rnkyBNKYb55ck2cN47yPfRKnDNxUSvYj--zg8To_PuL8iyGFZ7jDffUYcdVR7J8VQNYdz6JDhEXSA0GGIGilY3XBVsdMoK_1Lgsj41-o48DH3pUFfEuAFf4blE1D4h_sFoM",
   404    "qi": "CN3q5TMZO06DlK4onrJ687bPp2GE-fynd7ADPdf1ek3cXbeaFApVNp4w-i8zr7IVugQohn01i_jnkymw4UN-acoIzX2sGYhgDm6le1jyfv28bQ_Z5hT0rFNlPfGyK0kkPYUTxZ4ZCKpCYJT9C1nH58Yu4xFk4VR1zhULegjCCd4",
   405    "x5c": [
   406      "MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU="
   407    ],
   408    "x5t": "BhJU_fcg8sDkvT8zOaL-U1C",
   409    "x5t#S256": "IDJKS5LxImjvmuAl_Vx50Vj_dFdACSGW6DU8ADF"
   410  }`)
   411  
   412  	// Mismatched (leaf has different sum)
   413  	mismatchedThumbprints := []byte(`{
   414    "kty": "RSA",
   415    "kid": "bar",
   416    "alg": "foo",
   417    "n": "wN3v274Fr7grvZdXirEGkHlhYKh72gP-46MxQilMgANi6EaX2m0mYiMC60X1UmOhQNoVW0ItthMME-CGh7haA_Jeou_L6-EVOz-7lGu_J06VRl-mgkQZO0sYSkRY8Rsu7TW-pgnWWwZjSdgxN2gq7DvjjC4RLroV94Lgrb2Qwx6J5bZNOfj3pHmEWZ_eRFEH73Ct5RxwUKtNKx_XAmodZn9oFXBlN7F2Js-4DO-8UgbS7ALkTmhDzClT1GPfdLMusmXw4BXyV72vBOWrbUTdwk4pG8ahPQ0cGQ1ubaAmro_k3Bxg06voWPhXx7ALrpzmZCzr6YY-c5Y5rku4qXh-HQ",
   418    "e": "AQAB",
   419    "d": "RRM3xMvZ3YVopQ5_G_0rDLNsXOH6-apUr9LS4Y9JBtAvrGEcIe7VwHApq3ny0v870a5J19Vr6boIqVXQ2Or90kwL-O9JacHDiOTamd29KKbMb9fyGtWo88OBf5fbAv9pXyvQjEcZrqArD1eOyPlV5iXM6XfWT5X2KB-HuLIcFsVJSEb0yw943dEhZKkv2fySlVtKEhji2CfkMWP438G8auxwFPNIXmuvA1xvcAepOiI9I1Wy17txLOQg8MYBl98F7mxPUMpL3jm8-CSuxpknucFuFIrqIsbGmukSNp14APcu7bN0cJW5uVW-XtGbuioJkPjU2YJgfhIeMI8kuny5QQ",
   420    "p": "yRNzbsreZK9MqJgbVsbl7SX2MyyJW_JnFKGdyrXzMqCtzRS7XJ9L3SwdDG_ERgSCkT9PP2dax9fS7RghHNJIU_NlPnJqzBPvPyzbjho7hcGYGDU2UO8E3SBP1WKm1SnlYhm1uHwrHudAO0D5jhVYQfRwem-zX3QibrsxEyxSELM",
   421    "q": "9Yx0zzrhSxdE8ubryZfOyOw6cSbUdyCMgY3IFmEdb_UDZOQNMDCFj2RS1g6yFGKuaFqnL9ZRnmprikf20w-mu-LtLU_l0eK4U7pbAoB--pxFP_O6Yk3ZBu_YJ3FpimyX1v4OVZT-JOU_caKiTrPnlw3P7KbEc9iu_bOc8dE-_e8",
   422    "dp": "GwiFbXDS44B58vS4QDtvcCm5Zvnm4bi-SRTNbRJ3Rug5Vagi5Hn6LhsfMKvaHHvAvhxf4CtaFiIbFos28HQJC1he1T12xEct1DWIsxstw3bapu6IhesMoVoVwZ-IxIHkeALy3oG7HmWCyjSbGJIgEoX1lVBtMjkf4_lAyM4dnmc",
   423    "dq": "XYtXyMbOo3PG8Z6lfxRVU9gi346CbKu6u3RPIK94rnkyBNKYb55ck2cN47yPfRKnDNxUSvYj--zg8To_PuL8iyGFZ7jDffUYcdVR7J8VQNYdz6JDhEXSA0GGIGilY3XBVsdMoK_1Lgsj41-o48DH3pUFfEuAFf4blE1D4h_sFoM",
   424    "qi": "CN3q5TMZO06DlK4onrJ687bPp2GE-fynd7ADPdf1ek3cXbeaFApVNp4w-i8zr7IVugQohn01i_jnkymw4UN-acoIzX2sGYhgDm6le1jyfv28bQ_Z5hT0rFNlPfGyK0kkPYUTxZ4ZCKpCYJT9C1nH58Yu4xFk4VR1zhULegjCCd4",
   425    "x5c": [
   426      "MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU="
   427    ],
   428    "x5t": "BhJU_fcg8sDkvT8zOaL-U1ChXeX",
   429    "x5t#S256": "IDJKS5LxImjvmuAl_Vx50Vj_dFdACSGW6DU8ADFRdRX"
   430  }`)
   431  
   432  	var jwk2 JSONWebKey
   433  	err = jwk2.UnmarshalJSON(mismatchedThumbprints)
   434  	if err == nil {
   435  		t.Error("should not unmarshal JWK with mismatched thumbprints")
   436  	}
   437  
   438  	err = jwk2.UnmarshalJSON(shortThumbprints)
   439  	if err == nil {
   440  		t.Error("should not unmarshal JWK with too short thumbprints")
   441  	}
   442  }
   443  
   444  func TestKeyMismatchX509(t *testing.T) {
   445  	x5tSHA1 := sha1.Sum(testCertificates[0].Raw)
   446  	x5tSHA256 := sha256.Sum256(testCertificates[0].Raw)
   447  
   448  	jwk := JSONWebKey{
   449  		KeyID:                       "bar",
   450  		Algorithm:                   "foo",
   451  		Certificates:                testCertificates,
   452  		CertificateThumbprintSHA1:   x5tSHA1[:],
   453  		CertificateThumbprintSHA256: x5tSHA256[:],
   454  	}
   455  
   456  	for _, key := range []interface{}{
   457  		// None of these keys should match what's in the cert, so parsing should always fail.
   458  		ecTestKey256,
   459  		ecTestKey256.Public(),
   460  		ecTestKey384,
   461  		ecTestKey384.Public(),
   462  		ecTestKey521,
   463  		ecTestKey521.Public(),
   464  		rsaTestKey,
   465  		rsaTestKey.Public(),
   466  		ed25519PrivateKey,
   467  		ed25519PrivateKey.Public(),
   468  	} {
   469  		jwk.Key = key
   470  		raw, _ := jwk.MarshalJSON()
   471  
   472  		var jwk2 JSONWebKey
   473  		err := jwk2.UnmarshalJSON(raw)
   474  		if err == nil {
   475  			t.Error("should not unmarshal JWK with key/cert mismatch")
   476  		}
   477  	}
   478  }
   479  
   480  func TestMarshalUnmarshal(t *testing.T) {
   481  	kid := "DEADBEEF"
   482  
   483  	for i, key := range []interface{}{
   484  		ecTestKey256,
   485  		ecTestKey256.Public(),
   486  		ecTestKey384,
   487  		ecTestKey384.Public(),
   488  		ecTestKey521,
   489  		ecTestKey521.Public(),
   490  		rsaTestKey,
   491  		rsaTestKey.Public(),
   492  		ed25519PrivateKey,
   493  		ed25519PrivateKey.Public(),
   494  	} {
   495  		for _, use := range []string{"", "sig", "enc"} {
   496  			jwk := JSONWebKey{Key: key, KeyID: kid, Algorithm: "foo"}
   497  			if use != "" {
   498  				jwk.Use = use
   499  			}
   500  
   501  			jsonbar, err := jwk.MarshalJSON()
   502  			if err != nil {
   503  				t.Error("problem marshaling", i, err)
   504  			}
   505  
   506  			var jwk2 JSONWebKey
   507  			err = jwk2.UnmarshalJSON(jsonbar)
   508  			if err != nil {
   509  				t.Fatal("problem unmarshalling", i, err)
   510  			}
   511  
   512  			jsonbar2, err := jwk2.MarshalJSON()
   513  			if err != nil {
   514  				t.Fatal("problem marshaling", i, err)
   515  			}
   516  
   517  			if !bytes.Equal(jsonbar, jsonbar2) {
   518  				t.Error("roundtrip should not lose information", i)
   519  			}
   520  			if jwk2.KeyID != kid {
   521  				t.Error("kid did not roundtrip JSON marshalling", i)
   522  			}
   523  
   524  			if jwk2.Algorithm != "foo" {
   525  				t.Error("alg did not roundtrip JSON marshalling", i)
   526  			}
   527  
   528  			if jwk2.Use != use {
   529  				t.Error("use did not roundtrip JSON marshalling", i)
   530  			}
   531  		}
   532  	}
   533  }
   534  
   535  func TestMarshalNonPointer(t *testing.T) {
   536  	type EmbedsKey struct {
   537  		Key JSONWebKey
   538  	}
   539  
   540  	keyJSON := []byte(`{
   541  		"e": "AQAB",
   542  		"kty": "RSA",
   543  		"n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw"
   544  	}`)
   545  	var parsedKey JSONWebKey
   546  	err := json.Unmarshal(keyJSON, &parsedKey)
   547  	if err != nil {
   548  		t.Errorf("Error unmarshalling key: %v", err)
   549  		return
   550  	}
   551  	ek := EmbedsKey{
   552  		Key: parsedKey,
   553  	}
   554  	out, err := json.Marshal(ek)
   555  	if err != nil {
   556  		t.Errorf("Error marshalling JSON: %v", err)
   557  		return
   558  	}
   559  	expected := "{\"Key\":{\"kty\":\"RSA\",\"n\":\"vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw\",\"e\":\"AQAB\"}}"
   560  	if string(out) != expected {
   561  		t.Error("Failed to marshal embedded non-pointer JWK properly:", string(out))
   562  	}
   563  }
   564  
   565  func TestMarshalUnmarshalInvalid(t *testing.T) {
   566  	// Make an invalid curve coordinate by creating a byte array that is one
   567  	// byte too large, and setting the first byte to 1 (otherwise it's just zero).
   568  	invalidCoord := make([]byte, curveSize(ecTestKey256.Curve)+1)
   569  	invalidCoord[0] = 1
   570  
   571  	keys := []interface{}{
   572  		// Empty keys
   573  		&rsa.PrivateKey{},
   574  		&ecdsa.PrivateKey{},
   575  		// Invalid keys
   576  		&ecdsa.PrivateKey{
   577  			PublicKey: ecdsa.PublicKey{
   578  				// Missing values in pub key
   579  				Curve: elliptic.P256(),
   580  			},
   581  		},
   582  		&ecdsa.PrivateKey{
   583  			PublicKey: ecdsa.PublicKey{
   584  				// Invalid curve
   585  				Curve: nil,
   586  				X:     ecTestKey256.X,
   587  				Y:     ecTestKey256.Y,
   588  			},
   589  		},
   590  		&ecdsa.PrivateKey{
   591  			// Valid pub key, but missing priv key values
   592  			PublicKey: ecTestKey256.PublicKey,
   593  		},
   594  		&ecdsa.PrivateKey{
   595  			// Invalid pub key, values too large
   596  			PublicKey: ecdsa.PublicKey{
   597  				Curve: ecTestKey256.Curve,
   598  				X:     big.NewInt(0).SetBytes(invalidCoord),
   599  				Y:     big.NewInt(0).SetBytes(invalidCoord),
   600  			},
   601  			D: ecTestKey256.D,
   602  		},
   603  		nil,
   604  	}
   605  
   606  	for i, key := range keys {
   607  		jwk := JSONWebKey{Key: key}
   608  		_, err := jwk.MarshalJSON()
   609  		if err == nil {
   610  			t.Error("managed to serialize invalid key", i)
   611  		}
   612  	}
   613  }
   614  
   615  func TestWebKeyVectorsInvalid(t *testing.T) {
   616  	keys := []string{
   617  		// Invalid JSON
   618  		"{X",
   619  		// Empty key
   620  		"{}",
   621  		// Invalid RSA keys
   622  		`{"kty":"RSA"}`,
   623  		`{"kty":"RSA","e":""}`,
   624  		`{"kty":"RSA","e":"XXXX"}`,
   625  		`{"kty":"RSA","d":"XXXX"}`,
   626  		// Invalid EC keys
   627  		`{"kty":"EC","crv":"ABC"}`,
   628  		`{"kty":"EC","crv":"P-256"}`,
   629  		`{"kty":"EC","crv":"P-256","d":"XXX"}`,
   630  		`{"kty":"EC","crv":"ABC","d":"dGVzdA","x":"dGVzdA"}`,
   631  		`{"kty":"EC","crv":"P-256","d":"dGVzdA","x":"dGVzdA"}`,
   632  	}
   633  
   634  	for _, key := range keys {
   635  		var jwk2 JSONWebKey
   636  		err := jwk2.UnmarshalJSON([]byte(key))
   637  		if err == nil {
   638  			t.Error("managed to parse invalid key:", key)
   639  		}
   640  	}
   641  }
   642  
   643  // Test vectors from RFC 7520
   644  var cookbookJWKs = []string{
   645  	// EC Public
   646  	stripWhitespace(`{
   647       "kty": "EC",
   648       "kid": "bilbo.baggins@hobbiton.example",
   649       "use": "sig",
   650       "crv": "P-521",
   651       "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
   652           A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
   653       "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
   654           SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
   655     }`),
   656  
   657  	//ED Private
   658  	stripWhitespace(`{
   659       "kty": "OKP",
   660       "crv": "Ed25519",
   661       "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
   662       "d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A"
   663     }`),
   664  
   665  	// EC Private
   666  	stripWhitespace(`{
   667       "kty": "EC",
   668       "kid": "bilbo.baggins@hobbiton.example",
   669       "use": "sig",
   670       "crv": "P-521",
   671       "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
   672             A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
   673       "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
   674             SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1",
   675       "d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zb
   676             KipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt"
   677     }`),
   678  
   679  	// RSA Public
   680  	stripWhitespace(`{
   681       "kty": "RSA",
   682       "kid": "bilbo.baggins@hobbiton.example",
   683       "use": "sig",
   684       "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
   685           -O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
   686           wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
   687           oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
   688           3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
   689           LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
   690           HdrNP5zw",
   691       "e": "AQAB"
   692     }`),
   693  
   694  	// RSA Private
   695  	stripWhitespace(`{"kty":"RSA",
   696        "kid":"juliet@capulet.lit",
   697        "use":"enc",
   698        "n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy
   699             O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP
   700             8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0
   701             Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X
   702             OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1
   703             _I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
   704        "e":"AQAB",
   705        "d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS
   706             NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U
   707             vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu
   708             ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu
   709             rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a
   710             hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
   711        "p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf
   712             QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8
   713             UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
   714        "q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I
   715             edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK
   716             rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
   717        "dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3
   718             tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w
   719             Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
   720        "dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9
   721             GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy
   722             mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
   723        "qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq
   724             abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o
   725             Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}`),
   726  
   727  	// X.509 Certificate Chain
   728  	stripWhitespace(`{"kty":"RSA",
   729        "use":"sig",
   730        "kid":"1b94c",
   731        "n":"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08
   732             PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q
   733             u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a
   734             YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH
   735             MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv
   736             VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ",
   737        "e":"AQAB",
   738        "x5c":
   739             ["MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB
   740             gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD
   741             VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1
   742             wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg
   743             NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV
   744             QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w
   745             YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH
   746             YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66
   747             s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6
   748             SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn
   749             fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq
   750             PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk
   751             aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA
   752             QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL
   753             +9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1
   754             zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL
   755             2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo
   756             4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq
   757             gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]}`),
   758  }
   759  
   760  // SHA-256 thumbprints of the above keys, hex-encoded
   761  var cookbookJWKThumbprints = []string{
   762  	"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
   763  	"90facafea9b1556698540f70c0117a22ea37bd5cf3ed3c47093c1707282b4b89",
   764  	"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
   765  	"f63838e96077ad1fc01c3f8405774dedc0641f558ebb4b40dccf5f9b6d66a932",
   766  	"0fc478f8579325fcee0d4cbc6d9d1ce21730a6e97e435d6008fb379b0ebe47d4",
   767  	"0ddb05bfedbec2070fa037324ba397396561d3425d6d69245570c261dc49dee3",
   768  }
   769  
   770  func TestWebKeyVectorsValid(t *testing.T) {
   771  	for _, key := range cookbookJWKs {
   772  		var jwk2 JSONWebKey
   773  		err := jwk2.UnmarshalJSON([]byte(key))
   774  		if err != nil {
   775  			t.Error("unable to parse valid key:", key, err)
   776  		}
   777  	}
   778  }
   779  
   780  func TestEd25519Serialization(t *testing.T) {
   781  	jwk := JSONWebKey{
   782  		Key: ed25519PrivateKey,
   783  	}
   784  	serialized, _ := json.Marshal(jwk)
   785  
   786  	var jwk2 JSONWebKey
   787  	json.Unmarshal(serialized, &jwk2)
   788  
   789  	assert.True(t, bytes.Equal(
   790  		[]byte(jwk.Key.(ed25519.PrivateKey).Public().(ed25519.PublicKey)),
   791  		[]byte(jwk2.Key.(ed25519.PrivateKey).Public().(ed25519.PublicKey))))
   792  }
   793  
   794  func TestThumbprint(t *testing.T) {
   795  	for i, key := range cookbookJWKs {
   796  		var jwk2 JSONWebKey
   797  		err := jwk2.UnmarshalJSON([]byte(key))
   798  		if err != nil {
   799  			t.Error("unable to parse valid key:", key, err)
   800  		}
   801  
   802  		tp, err := jwk2.Thumbprint(crypto.SHA256)
   803  		if err != nil {
   804  			t.Error("unable to compute thumbprint:", key, err)
   805  		}
   806  
   807  		tpHex := hex.EncodeToString(tp)
   808  		if cookbookJWKThumbprints[i] != tpHex {
   809  			t.Error("incorrect thumbprint:", i, cookbookJWKThumbprints[i], tpHex)
   810  		}
   811  	}
   812  }
   813  
   814  func TestMarshalUnmarshalJWKSet(t *testing.T) {
   815  	jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
   816  	jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
   817  	var set JSONWebKeySet
   818  	set.Keys = append(set.Keys, jwk1)
   819  	set.Keys = append(set.Keys, jwk2)
   820  
   821  	jsonbar, err := json.Marshal(&set)
   822  	if err != nil {
   823  		t.Error("problem marshalling set", err)
   824  	}
   825  	var set2 JSONWebKeySet
   826  	err = json.Unmarshal(jsonbar, &set2)
   827  	if err != nil {
   828  		t.Fatal("problem unmarshalling set", err)
   829  	}
   830  	jsonbar2, err := json.Marshal(&set2)
   831  	if err != nil {
   832  		t.Fatal("problem marshalling set", err)
   833  	}
   834  	if !bytes.Equal(jsonbar, jsonbar2) {
   835  		t.Error("roundtrip should not lose information")
   836  	}
   837  }
   838  
   839  func TestJWKSetKey(t *testing.T) {
   840  	jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
   841  	jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
   842  	var set JSONWebKeySet
   843  	set.Keys = append(set.Keys, jwk1)
   844  	set.Keys = append(set.Keys, jwk2)
   845  	k := set.Key("ABCDEFG")
   846  	if len(k) != 1 {
   847  		t.Errorf("method should return slice with one key not %d", len(k))
   848  	}
   849  	if k[0].KeyID != "ABCDEFG" {
   850  		t.Error("method should return key with ID ABCDEFG")
   851  	}
   852  }
   853  
   854  func TestJWKSymmetricKey(t *testing.T) {
   855  	sample1 := `{"kty":"oct","alg":"A128KW","k":"GawgguFyGrWKav7AX4VKUg"}`
   856  	sample2 := `{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow","kid":"HMAC key used in JWS spec Appendix A.1 example"}`
   857  
   858  	var jwk1 JSONWebKey
   859  	json.Unmarshal([]byte(sample1), &jwk1)
   860  
   861  	if jwk1.Algorithm != "A128KW" {
   862  		t.Errorf("expected Algorithm to be A128KW, but was '%s'", jwk1.Algorithm)
   863  	}
   864  	expected1 := fromHexBytes("19ac2082e1721ab58a6afec05f854a52")
   865  	if !bytes.Equal(jwk1.Key.([]byte), expected1) {
   866  		t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected1), hex.EncodeToString(jwk1.Key.([]byte)))
   867  	}
   868  
   869  	var jwk2 JSONWebKey
   870  	json.Unmarshal([]byte(sample2), &jwk2)
   871  
   872  	if jwk2.KeyID != "HMAC key used in JWS spec Appendix A.1 example" {
   873  		t.Errorf("expected KeyID to be 'HMAC key used in JWS spec Appendix A.1 example', but was '%s'", jwk2.KeyID)
   874  	}
   875  	expected2 := fromHexBytes(`
   876      0323354b2b0fa5bc837e0665777ba68f5ab328e6f054c928a90f84b2d2502ebf
   877      d3fb5a92d20647ef968ab4c377623d223d2e2172052e4f08c0cd9af567d080a3`)
   878  	if !bytes.Equal(jwk2.Key.([]byte), expected2) {
   879  		t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected2), hex.EncodeToString(jwk2.Key.([]byte)))
   880  	}
   881  }
   882  
   883  func TestJWKSymmetricRoundtrip(t *testing.T) {
   884  	jwk1 := JSONWebKey{Key: []byte{1, 2, 3, 4}}
   885  	marshaled, err := jwk1.MarshalJSON()
   886  	if err != nil {
   887  		t.Error("failed to marshal valid JWK object", err)
   888  	}
   889  
   890  	var jwk2 JSONWebKey
   891  	err = jwk2.UnmarshalJSON(marshaled)
   892  	if err != nil {
   893  		t.Error("failed to unmarshal valid JWK object", err)
   894  	}
   895  
   896  	if !bytes.Equal(jwk1.Key.([]byte), jwk2.Key.([]byte)) {
   897  		t.Error("round-trip of symmetric JWK gave different raw keys")
   898  	}
   899  }
   900  
   901  func TestJWKSymmetricInvalid(t *testing.T) {
   902  	invalid := JSONWebKey{}
   903  	_, err := invalid.MarshalJSON()
   904  	if err == nil {
   905  		t.Error("excepted error on marshaling invalid symmetric JWK object")
   906  	}
   907  
   908  	var jwk JSONWebKey
   909  	err = jwk.UnmarshalJSON([]byte(`{"kty":"oct"}`))
   910  	if err == nil {
   911  		t.Error("excepted error on unmarshaling invalid symmetric JWK object")
   912  	}
   913  }
   914  
   915  func TestJWKIsPublic(t *testing.T) {
   916  	bigInt := big.NewInt(0)
   917  	eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
   918  	rsaPub := rsa.PublicKey{bigInt, 1}
   919  
   920  	cases := []struct {
   921  		key              interface{}
   922  		expectedIsPublic bool
   923  	}{
   924  		{&eccPub, true},
   925  		{&ecdsa.PrivateKey{eccPub, bigInt}, false},
   926  		{&rsaPub, true},
   927  		{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, false},
   928  		{ed25519PublicKey, true},
   929  		{ed25519PrivateKey, false},
   930  	}
   931  
   932  	for _, tc := range cases {
   933  		k := &JSONWebKey{Key: tc.key}
   934  		if public := k.IsPublic(); public != tc.expectedIsPublic {
   935  			t.Errorf("expected IsPublic to return %t, got %t", tc.expectedIsPublic, public)
   936  		}
   937  	}
   938  }
   939  
   940  func TestJWKValid(t *testing.T) {
   941  	bigInt := big.NewInt(0)
   942  	eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
   943  	rsaPub := rsa.PublicKey{bigInt, 1}
   944  	edPubEmpty := ed25519.PublicKey([]byte{})
   945  	edPrivEmpty := ed25519.PublicKey([]byte{})
   946  
   947  	cases := []struct {
   948  		key              interface{}
   949  		expectedValidity bool
   950  	}{
   951  		{nil, false},
   952  		{&ecdsa.PublicKey{}, false},
   953  		{&eccPub, true},
   954  		{&ecdsa.PrivateKey{}, false},
   955  		{&ecdsa.PrivateKey{eccPub, bigInt}, true},
   956  		{&rsa.PublicKey{}, false},
   957  		{&rsaPub, true},
   958  		{&rsa.PrivateKey{}, false},
   959  		{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, true},
   960  		{ed25519PublicKey, true},
   961  		{ed25519PrivateKey, true},
   962  		{edPubEmpty, false},
   963  		{edPrivEmpty, false},
   964  	}
   965  
   966  	for _, tc := range cases {
   967  		k := &JSONWebKey{Key: tc.key}
   968  		valid := k.Valid()
   969  		if valid != tc.expectedValidity {
   970  			t.Errorf("expected Valid to return %t, got %t", tc.expectedValidity, valid)
   971  		}
   972  		if valid {
   973  			wasPublic := k.IsPublic()
   974  			p := k.Public() // all aforemention keys are asymmetric
   975  			if !p.Valid() {
   976  				t.Errorf("unable to derive public key from valid asymmetric key")
   977  			}
   978  			if wasPublic != k.IsPublic() {
   979  				t.Errorf("original key was touched during public key derivation")
   980  			}
   981  		}
   982  	}
   983  }
   984  
   985  func TestJWKBufferSizeCheck(t *testing.T) {
   986  	key := `{
   987  		"kty":"EC",
   988  		"crv":"P-256",
   989  		"x":"m9GSmJ5iGmAYlMlaOJGSFN_CjN9cIn8GGYExP-C0FBiIXlWTNvGN38R9WdrHcppfsKF0FXMOMyutpHIRaiMxYSA",
   990  		"y":"ZaPcRZ3q_7T3h-Gwz2i-T2JjJXfj6YVGgKHcFz5zqmg"}`
   991  	var jwk JSONWebKey
   992  	jwk.UnmarshalJSON([]byte(key))
   993  	jwk.Valid() // true
   994  	// panic: square/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)
   995  	// github.com/square/go-jose.newFixedSizeBuffer(0xc420014557, 0x41, 0x41, 0x20, 0x0)
   996  	jwk.Thumbprint(crypto.SHA256)
   997  }
   998  
   999  func TestJWKPaddingPrivateX(t *testing.T) {
  1000  	key := `{
  1001      "kty": "EC",
  1002      "crv": "P-256",
  1003      "x": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
  1004      "y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
  1005      "d": "nIVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
  1006    }`
  1007  	var jwk JSONWebKey
  1008  	err := jwk.UnmarshalJSON([]byte(key))
  1009  	if err == nil {
  1010  		t.Errorf("Expected key with short x to fail unmarshalling")
  1011  	}
  1012  	if !strings.Contains(err.Error(), "wrong length for x") {
  1013  		t.Errorf("Wrong error for short x, got %q", err)
  1014  	}
  1015  	if jwk.Valid() {
  1016  		t.Errorf("Expected key to be invalid, but it was valid.")
  1017  	}
  1018  }
  1019  
  1020  func TestJWKPaddingPrivateY(t *testing.T) {
  1021  	key := `{
  1022      "kty": "EC",
  1023      "crv": "P-256",
  1024      "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
  1025      "y": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
  1026      "d": "nIVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
  1027    }`
  1028  	var jwk JSONWebKey
  1029  	err := jwk.UnmarshalJSON([]byte(key))
  1030  	if err == nil {
  1031  		t.Errorf("Expected key with short x to fail unmarshalling")
  1032  	}
  1033  	if !strings.Contains(err.Error(), "wrong length for y") {
  1034  		t.Errorf("Wrong error for short y, got %q", err)
  1035  	}
  1036  	if jwk.Valid() {
  1037  		t.Errorf("Expected key to be invalid, but it was valid.")
  1038  	}
  1039  }
  1040  
  1041  func TestJWKPaddingPrivateD(t *testing.T) {
  1042  	key := `{
  1043      "kty": "EC",
  1044      "crv": "P-256",
  1045      "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
  1046      "y": "qnPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
  1047      "d": "IVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
  1048    }`
  1049  	var jwk JSONWebKey
  1050  	err := jwk.UnmarshalJSON([]byte(key))
  1051  	if err == nil {
  1052  		t.Errorf("Expected key with short x to fail unmarshalling")
  1053  	}
  1054  	if !strings.Contains(err.Error(), "wrong length for d") {
  1055  		t.Errorf("Wrong error for short d, got %q", err)
  1056  	}
  1057  	if jwk.Valid() {
  1058  		t.Errorf("Expected key to be invalid, but it was valid.")
  1059  	}
  1060  }
  1061  
  1062  func TestJWKPaddingX(t *testing.T) {
  1063  	key := `{
  1064      "kty": "EC",
  1065      "crv": "P-256",
  1066      "x": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
  1067      "y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs"
  1068    }`
  1069  	var jwk JSONWebKey
  1070  	err := jwk.UnmarshalJSON([]byte(key))
  1071  	if err == nil {
  1072  		t.Errorf("Expected key with short x to fail unmarshalling")
  1073  	}
  1074  	if !strings.Contains(err.Error(), "wrong length for x") {
  1075  		t.Errorf("Wrong error for short x, got %q", err)
  1076  	}
  1077  	if jwk.Valid() {
  1078  		t.Errorf("Expected key to be invalid, but it was valid.")
  1079  	}
  1080  }
  1081  
  1082  func TestJWKPaddingY(t *testing.T) {
  1083  	key := `{
  1084      "kty": "EC",
  1085      "crv": "P-256",
  1086      "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
  1087      "y": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ"
  1088    }`
  1089  	var jwk JSONWebKey
  1090  	err := jwk.UnmarshalJSON([]byte(key))
  1091  	if err == nil {
  1092  		t.Errorf("Expected key with short y to fail unmarshalling")
  1093  	}
  1094  	if !strings.Contains(err.Error(), "wrong length for y") {
  1095  		t.Errorf("Wrong error for short y, got %q", err)
  1096  	}
  1097  	if jwk.Valid() {
  1098  		t.Errorf("Expected key to be invalid, but it was valid.")
  1099  	}
  1100  }
  1101  

View as plain text