...

Source file src/gopkg.in/go-jose/go-jose.v2/jws_test.go

Documentation: gopkg.in/go-jose/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  	"crypto/x509"
    21  	"encoding/base64"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  )
    27  
    28  const trustedCA = `
    29  -----BEGIN CERTIFICATE-----
    30  MIIE8DCCAtigAwIBAgIJAPgBgSSm5PSpMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
    31  BAMMCVRydXN0ZWRDQTAeFw0yMDEwMDQyMjU0MzlaFw00MDEwMDQyMjU0MzlaMBQx
    32  EjAQBgNVBAMMCVRydXN0ZWRDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
    33  ggIBAJ+o4csEF8uhudNfBgOilhJbJT4D+gLTJT2l7+YEaRnJsyKnaaMYTZl3j+6z
    34  8eRPCIx0wkeVvy9H0XXARkXPylycpFrFdOOE+jG7n/KpglOgD4cnpJEc2cZOGnxi
    35  d1EiVEoFS9iD1L+SZG0XLfczfGCi970lK1UfBkADrjxXPdUmml+LFlQbLwdjw29e
    36  b8heaYep3ltXpyfy2W0mgLakqV+mWqPzcp4dWjohSrOWr/iZSWTVLKlXyKvj3nfC
    37  lcXU5FqDSlU5m6tbxhfscEvG2n12TzpGTNSez7my3qxNaAFf1rd/+RvJYjJ4gelH
    38  O9ZF9POqOxdoRgZca2SQetRaUlrYbJTY9cjKEJLloo83I65vWDqgMREChzpMorKz
    39  ZCeqCVgsgAdo75kiCW1fHY6MvBFk2x9kfZqwv/Dp+vyv22bOVa7ob84CEWbRYMIt
    40  wCXRXrewAkvCHFvB6Uoz2Qn2c+3jWzlyRNCucfaPtWnNzRaG6lVm9ieucQI/+Ij4
    41  XwuZmmPzOAvKlXadVXNlnsExkrAabc6UJEyqKI7raSeJaR/8RLLfxTDSv3UuWY8v
    42  I2QMdS1f6fC8VJKTYMfbdnIw4RQ9Eqi2EmNPgJ4I2mTilG12pRxl/dvfFTl/7/TM
    43  Mu6jCLNvJnm3B96at1Y4evWoee51EcvpkNnwotyPLtJFpEMLAgMBAAGjRTBDMB0G
    44  A1UdDgQWBBTJ8bqL9u+G1ykEpl9uakSgZGq3JDASBgNVHRMBAf8ECDAGAQH/AgEB
    45  MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAB9WBvqUM+tM+1JAS
    46  YmUmRKjYlrKUYwNTzgrAyyiYLWzp9cmcw+3hbAjDV0Lu1Im8QQ0eRdq2H8103JYd
    47  +nJJx+zlJ04s3pms02uZf8s05XJPSqlYb03uyfZ5uQcOAsRAPHeXaxEmZ/K6PGqO
    48  14O3anXb5u+Qq2cb7DGG/Qcek8iX8vI5RqxvLGOOD9z9mpqE9M6aTsjuBVSLM3aQ
    49  yIIkRk3deXiOfZd8d+0pShKgVBSrAC8c7A+Yps/r/vSGmN8L+LDoNzfx4NaPLBzu
    50  dgiKVpYYgjFEnDzYItWpyxkPVjfMxPEQkz8choJaYNuoROpZtEnSFb4MFHlYGqhO
    51  ZYETsYL3BRCHp0WysA3KuXTyA2Tmr+503Xw0btO2ieGEOCe3v/Yc7WGQX3RRAdci
    52  2TkBISG6QlH5FzeV11hPriKEMSFHFdJvVrtRORtkGPeE6DUjHQ8MSK8Vm0niKT5P
    53  l9GLvIrBN00Pa+YUX0j1xaCY0aj0oxKDFIdyWTn6aR/q9M7CfW6H0fNjPu56+jit
    54  q+yQijumIkI5MTlbj0ja51yN62/tNhpTZx/NXpWjgZ+S/668/BJ2veV99PGuQCss
    55  jlhHfN8RbHaPuKTKLLslkTvtpIYTc6F9TmcnVAdyKxN8e1XHcV4WrIOzgegVE4IF
    56  48TF8WeXgGnsH4Bvob3cZcqWA+w=
    57  -----END CERTIFICATE-----`
    58  
    59  const intermediateCA = `
    60  -----BEGIN CERTIFICATE-----
    61  MIIEDzCCAfegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJVHJ1
    62  c3RlZENBMB4XDTIwMTAwNDIzMDMzM1oXDTQwMTAwNDIzMDMzM1owGTEXMBUGA1UE
    63  AwwOSW50ZXJtZWRpYXRlQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
    64  AQDiKADoUoaNvD4yCLPySuPR1saLWHNRlt2nqbd7smwB1quNKnKwAKKnLyaBUHIC
    65  FrQjCTA7IF7KUndVU0vutMFzn6hKuliZMYbwDQgx6x8u34m8Ar8cAg/AJPgT5Kk6
    66  Ds8soUaTzRG/GXVjGll0ArjRp97LmOW1Tc53R4YJji6eTThgb4Al6XDou2AeEMNY
    67  C46yqafwzOvHOnzSQwy8IwdcFjNKry15pvutIK3UhZscAmfbNEN5ou3miWcz3PuV
    68  GORxKAqlA4mYoJWE2AF52fgNTYcTFCDdiThaFSBzgqEgFoDzzROhf1B+/bSJ4gUL
    69  K9YQxpXVmt8/tlvXjNygDj1LAgMBAAGjZjBkMB0GA1UdDgQWBBTZZOBbEfV70Ocm
    70  9RIM16yhAw4SyjAfBgNVHSMEGDAWgBTJ8bqL9u+G1ykEpl9uakSgZGq3JDASBgNV
    71  HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC
    72  AgEADfEtLh3YDabrTsx+KmJ1f8ybwdltgI3gPiubd5RcYcoO3Pd33/INJDMkJYfL
    73  CrSDLI5Y94szOUhkP/rSwrUgJErnPSPUEW11GgA230d7vjc3bFJO/bPb2ZAwm/eC
    74  7dMMyyDH/2Wty7h7SOuXXJljZYIvuavJymZxsmkDAu7MtdntHVLr5bruEYvM9IKa
    75  d9YZSchRP1Q3kIZuTmNvBgLGwrVw/UcOpczajULNNzPUNPDFs9Zo04tx/YF1R1fO
    76  GUhif13DMk+6JU7zUXZL3iqOSkxBRrlMQX6nKAQ68cMqO2UsrfXBqH5xm3O9+Nxs
    77  fN3CkkTcyBcvVFMaMe0670lCh3DcFOMDt2YdlqS5tEsBn3TdOFKSjv2dVnT2eeXc
    78  q5IvuC4nkEXzZDROfQVrnraBhHOiyLAlfwhA1LHZGlJfNZaWRDdXHKV+pIMr2JyO
    79  v/hf9aaWzjwyy7FJwn3yrEwHGfBgx0vgKPj6l6N8qxQ6l1XMyANx4ExlpXfffx+C
    80  PWV9eeMi4Wh6V9641LesQnlOGgL5R03jQRjaicp3nvzsNElDEgPq0s9PE8s6weFK
    81  Bz5ykrw/Gg4QWmw6MfwjOX5Fu1oJF9ABoCFD5umvKhpoJkcT8aYM0+E1xiEAx64u
    82  Wq2b2GCGP4wMEZuqCcE72fiue295ovPkNsbEjTQk/ijWza0=
    83  -----END CERTIFICATE-----`
    84  
    85  func TestEmbeddedHMAC(t *testing.T) {
    86  	// protected: {"alg":"HS256", "jwk":{"kty":"oct", "k":"MTEx"}}, aka HMAC key.
    87  	msg := `{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ","protected":"eyJhbGciOiJIUzI1NiIsICJqd2siOnsia3R5Ijoib2N0IiwgImsiOiJNVEV4In19","signature":"lvo41ZZsuHwQvSh0uJtEXRR3vmuBJ7in6qMoD7p9jyo"}`
    88  
    89  	_, err := ParseSigned(msg)
    90  	if err == nil {
    91  		t.Error("should not allow parsing JWS with embedded JWK with HMAC key")
    92  	}
    93  }
    94  
    95  func TestCompactParseJWS(t *testing.T) {
    96  	// Should parse
    97  	msg := "eyJhbGciOiJYWVoifQ.cGF5bG9hZA.c2lnbmF0dXJl"
    98  	_, err := ParseSigned(msg)
    99  	if err != nil {
   100  		t.Error("Unable to parse valid message:", err)
   101  	}
   102  
   103  	// Should parse (detached signature missing payload)
   104  	msg = "eyJhbGciOiJYWVoifQ..c2lnbmF0dXJl"
   105  	_, err = ParseSigned(msg)
   106  	if err != nil {
   107  		t.Error("Unable to parse valid message:", err)
   108  	}
   109  
   110  	// Messages that should fail to parse
   111  	failures := []string{
   112  		// Not enough parts
   113  		"eyJhbGciOiJYWVoifQ.cGF5bG9hZA",
   114  		// Invalid signature
   115  		"eyJhbGciOiJYWVoifQ.cGF5bG9hZA.////",
   116  		// Invalid payload
   117  		"eyJhbGciOiJYWVoifQ.////.c2lnbmF0dXJl",
   118  		// Invalid header
   119  		"////.eyJhbGciOiJYWVoifQ.c2lnbmF0dXJl",
   120  		// Invalid header
   121  		"cGF5bG9hZA.cGF5bG9hZA.c2lnbmF0dXJl",
   122  	}
   123  
   124  	for i := range failures {
   125  		_, err = ParseSigned(failures[i])
   126  		if err == nil {
   127  			t.Error("Able to parse invalid message")
   128  		}
   129  	}
   130  }
   131  
   132  func TestFullParseJWS(t *testing.T) {
   133  	// Messages that should succeed to parse
   134  	successes := []string{
   135  		"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"},{\"protected\":\"e30\",\"signature\":\"CUJD\"}]}",
   136  	}
   137  
   138  	for i := range successes {
   139  		_, err := ParseSigned(successes[i])
   140  		if err != nil {
   141  			t.Error("Unble to parse valid message", err, successes[i])
   142  		}
   143  	}
   144  
   145  	// Messages that should fail to parse
   146  	failures := []string{
   147  		// Empty
   148  		"{}",
   149  		// Invalid JSON
   150  		"{XX",
   151  		// Invalid protected header
   152  		"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
   153  		// Invalid protected header
   154  		"{\"payload\":\"CUJD\",\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}",
   155  		// Invalid protected header
   156  		"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"###\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
   157  		// Invalid payload
   158  		"{\"payload\":\"###\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
   159  		// Invalid payload
   160  		"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"###\"}]}",
   161  	}
   162  
   163  	for i := range failures {
   164  		_, err := ParseSigned(failures[i])
   165  		if err == nil {
   166  			t.Error("Able to parse invalid message", err, failures[i])
   167  		}
   168  	}
   169  }
   170  
   171  func TestRejectUnprotectedJWSNonce(t *testing.T) {
   172  	// No need to test compact, since that's always protected
   173  
   174  	// Flattened JSON
   175  	input := `{
   176  		"header": { "nonce": "should-cause-an-error" },
   177  		"payload": "does-not-matter",
   178  		"signature": "does-not-matter"
   179  	}`
   180  	_, err := ParseSigned(input)
   181  	if err == nil {
   182  		t.Error("JWS with an unprotected nonce parsed as valid.")
   183  	} else if err != ErrUnprotectedNonce {
   184  		t.Errorf("Improper error for unprotected nonce: %v", err)
   185  	}
   186  
   187  	// Full JSON
   188  	input = `{
   189  		"payload": "does-not-matter",
   190   		"signatures": [{
   191   			"header": { "nonce": "should-cause-an-error" },
   192  			"signature": "does-not-matter"
   193  		}]
   194  	}`
   195  	_, err = ParseSigned(input)
   196  	if err == nil {
   197  		t.Error("JWS with an unprotected nonce parsed as valid.")
   198  	} else if err != ErrUnprotectedNonce {
   199  		t.Errorf("Improper error for unprotected nonce: %v", err)
   200  	}
   201  }
   202  
   203  func TestVerifyFlattenedWithIncludedUnprotectedKey(t *testing.T) {
   204  	input := `{
   205  			"header": {
   206  					"alg": "RS256",
   207  					"jwk": {
   208  							"e": "AQAB",
   209  							"kty": "RSA",
   210  							"n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ"
   211  					}
   212  			},
   213  			"payload": "Zm9vCg",
   214  			"signature": "hRt2eYqBd_MyMRNIh8PEIACoFtmBi7BHTLBaAhpSU6zyDAFdEBaX7us4VB9Vo1afOL03Q8iuoRA0AT4akdV_mQTAQ_jhTcVOAeXPr0tB8b8Q11UPQ0tXJYmU4spAW2SapJIvO50ntUaqU05kZd0qw8-noH1Lja-aNnU-tQII4iYVvlTiRJ5g8_CADsvJqOk6FcHuo2mG643TRnhkAxUtazvHyIHeXMxydMMSrpwUwzMtln4ZJYBNx4QGEq6OhpAD_VSp-w8Lq5HOwGQoNs0bPxH1SGrArt67LFQBfjlVr94E1sn26p4vigXm83nJdNhWAMHHE9iV67xN-r29LT-FjA"
   215  	}`
   216  
   217  	jws, err := ParseSigned(input)
   218  	if err != nil {
   219  		t.Fatal("Unable to parse valid message", err)
   220  	}
   221  	if len(jws.Signatures) != 1 {
   222  		t.Error("Too many or too few signatures.")
   223  	}
   224  	sig := jws.Signatures[0]
   225  	if sig.Header.JSONWebKey == nil {
   226  		t.Error("No JWK in signature header.")
   227  	}
   228  	payload, err := jws.Verify(sig.Header.JSONWebKey)
   229  	if err != nil {
   230  		t.Errorf("Signature did not validate: %v", err)
   231  	}
   232  	if string(payload) != "foo\n" {
   233  		t.Errorf("Payload was incorrect: '%s' should have been 'foo\\n'", string(payload))
   234  	}
   235  }
   236  
   237  // Test verification of a detached signature
   238  func TestDetachedVerifyJWS(t *testing.T) {
   239  	rsaPublicKey, err := x509.ParsePKIXPublicKey(fromBase64Bytes(`
   240  		MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
   241  		91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
   242  		t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
   243  		NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
   244  		CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
   245  		zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  
   250  	sampleMessages := []string{
   251  		"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
   252  		"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
   253  	}
   254  
   255  	for _, msg := range sampleMessages {
   256  		obj, err := ParseSigned(msg)
   257  		if err != nil {
   258  			t.Error("unable to parse message", msg, err)
   259  			continue
   260  		}
   261  		payload := obj.payload
   262  		obj.payload = nil
   263  		err = obj.DetachedVerify(payload, rsaPublicKey)
   264  		if err != nil {
   265  			t.Error("unable to verify message", msg, err)
   266  			continue
   267  		}
   268  		idx, _, err := obj.DetachedVerifyMulti(payload, rsaPublicKey)
   269  		if idx != 0 || err != nil {
   270  			t.Error("unable to verify message", msg, err)
   271  			continue
   272  		}
   273  	}
   274  }
   275  
   276  func TestVerifyFlattenedWithPrivateProtected(t *testing.T) {
   277  	// The protected field contains a Private Header Parameter name, per
   278  	// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
   279  	// Base64-decoded, it's '{"nonce":"8HIepUNFZUa-exKTrXVf4g"}'
   280  	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"}`
   281  
   282  	jws, err := ParseSigned(input)
   283  	if err != nil {
   284  		t.Error("Unable to parse valid message.")
   285  	}
   286  	if len(jws.Signatures) != 1 {
   287  		t.Error("Too many or too few signatures.")
   288  	}
   289  	sig := jws.Signatures[0]
   290  	if sig.Header.JSONWebKey == nil {
   291  		t.Error("No JWK in signature header.")
   292  	}
   293  	payload, err := jws.Verify(sig.Header.JSONWebKey)
   294  	if err != nil {
   295  		t.Errorf("Signature did not validate: %v", err)
   296  	}
   297  	expected := "{\"contact\":[\"mailto:foo@bar.com\"]}"
   298  	if string(payload) != expected {
   299  		t.Errorf("Payload was incorrect: '%s' should have been '%s'", string(payload), expected)
   300  	}
   301  }
   302  
   303  // Test vectors generated with nimbus-jose-jwt
   304  func TestSampleNimbusJWSMessagesRSA(t *testing.T) {
   305  	rsaPublicKey, err := x509.ParsePKIXPublicKey(fromBase64Bytes(`
   306  		MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
   307  		91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
   308  		t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
   309  		NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
   310  		CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
   311  		zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
   312  	if err != nil {
   313  		panic(err)
   314  	}
   315  
   316  	rsaSampleMessages := []string{
   317  		"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
   318  		"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
   319  		"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
   320  		"eyJhbGciOiJQUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.UTtxjsv_6x4CdlAmZfAW6Lun3byMjJbcwRp_OlPH2W4MZaZar7aql052mIB_ddK45O9VUz2aphYVRvKPZY8WHmvlTUU30bk0z_cDJRYB9eIJVMOiRCYj0oNkz1iEZqsP0YgngxwuUDv4Q4A6aJ0Bo5E_rZo3AnrVHMHUjPp_ZRRSBFs30tQma1qQ0ApK4Gxk0XYCYAcxIv99e78vldVRaGzjEZmQeAVZx4tGcqZP20vG1L84nlhSGnOuZ0FhR8UjRFLXuob6M7EqtMRoqPgRYw47EI3fYBdeSivAg98E5S8R7R1NJc7ef-l03RvfUSY0S3_zBq_4PlHK6A-2kHb__w",
   321  		"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
   322  		"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
   323  	}
   324  
   325  	for _, msg := range rsaSampleMessages {
   326  		obj, err := ParseSigned(msg)
   327  		if err != nil {
   328  			t.Error("unable to parse message", msg, err)
   329  			continue
   330  		}
   331  		payload, err := obj.Verify(rsaPublicKey)
   332  		if err != nil {
   333  			t.Error("unable to verify message", msg, err)
   334  			continue
   335  		}
   336  		if string(payload) != "Lorem ipsum dolor sit amet" {
   337  			t.Error("payload is not what we expected for msg", msg)
   338  		}
   339  	}
   340  }
   341  
   342  // Test vectors generated with nimbus-jose-jwt
   343  func TestSampleNimbusJWSMessagesEC(t *testing.T) {
   344  	ecPublicKeyP256, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIg62jq6FyL1otEj9Up7S35BUrwGF9TVrAzrrY1rHUKZqYIGEg67u/imjgadVcr7y9Q32I0gB8W8FHqbqt696rA=="))
   345  	if err != nil {
   346  		panic(err)
   347  	}
   348  	ecPublicKeyP384, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEPXsVlqCtN2oTY+F+hFZm3M0ldYpb7IeeJM5wYmT0k1RaqzBFDhDMNnYK5Q5x+OyssZrAtHgYDFw02AVJhhng/eHRp7mqmL/vI3wbxJtrLKYldIbBA+9fYBQcKeibjlu5"))
   349  	if err != nil {
   350  		panic(err)
   351  	}
   352  	ecPublicKeyP521, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAa2w3MMJ5FWD6tSf68G+Wy5jIhWXOD3IA7pE5IC/myQzo1lWcD8KS57SM6nm4POtPcxyLmDhL7FLuh8DKoIZyvtAAdK8+tOQP7XXRlT2bkvzIuazp05It3TAPu00YzTIpKfDlc19Y1lvf7etrbFqhShD92B+hHmhT4ddrdbPCBDW8hvU="))
   353  	if err != nil {
   354  		panic(err)
   355  	}
   356  
   357  	ecPublicKeys := []interface{}{ecPublicKeyP256, ecPublicKeyP384, ecPublicKeyP521}
   358  
   359  	ecSampleMessages := []string{
   360  		"eyJhbGciOiJFUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.MEWJVlvGRQyzMEGOYm4rwuiwxrX-6LjnlbaRDAuhwmnBm2Gtn7pRpGXRTMFZUXsSGDz2L1p-Hz1qn8j9bFIBtQ",
   361  		"eyJhbGciOiJFUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.nbdjPnJPYQtVNNdBIx8-KbFKplTxrz-hnW5UNhYUY7SBkwHK4NZnqc2Lv4DXoA0aWHq9eiypgOh1kmyPWGEmqKAHUx0xdIEkBoHk3ZsbmhOQuq2jL_wcMUG6nTWNhLrB",
   362  		"eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g",
   363  	}
   364  
   365  	for i, msg := range ecSampleMessages {
   366  		obj, err := ParseSigned(msg)
   367  		if err != nil {
   368  			t.Error("unable to parse message", msg, err)
   369  			continue
   370  		}
   371  		payload, err := obj.Verify(ecPublicKeys[i])
   372  		if err != nil {
   373  			t.Error("unable to verify message", msg, err)
   374  			continue
   375  		}
   376  		if string(payload) != "Lorem ipsum dolor sit amet" {
   377  			t.Error("payload is not what we expected for msg", msg)
   378  		}
   379  	}
   380  }
   381  
   382  // Test vectors generated with nimbus-jose-jwt
   383  func TestSampleNimbusJWSMessagesHMAC(t *testing.T) {
   384  	hmacTestKey := fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D")
   385  
   386  	hmacSampleMessages := []string{
   387  		"eyJhbGciOiJIUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.W5tc_EUhxexcvLYEEOckyyvdb__M5DQIVpg6Nmk1XGM",
   388  		"eyJhbGciOiJIUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.sBu44lXOJa4Nd10oqOdYH2uz3lxlZ6o32QSGHaoGdPtYTDG5zvSja6N48CXKqdAh",
   389  		"eyJhbGciOiJIUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.M0yR4tmipsORIix-BitIbxEPGaxPchDfj8UNOpKuhDEfnb7URjGvCKn4nOlyQ1z9mG1FKbwnqR1hOVAWSzAU_w",
   390  	}
   391  
   392  	for _, msg := range hmacSampleMessages {
   393  		obj, err := ParseSigned(msg)
   394  		if err != nil {
   395  			t.Error("unable to parse message", msg, err)
   396  			continue
   397  		}
   398  		payload, err := obj.Verify(hmacTestKey)
   399  		if err != nil {
   400  			t.Error("unable to verify message", msg, err)
   401  			continue
   402  		}
   403  		if string(payload) != "Lorem ipsum dolor sit amet" {
   404  			t.Error("payload is not what we expected for msg", msg)
   405  		}
   406  	}
   407  }
   408  
   409  func TestHeaderFieldsCompact(t *testing.T) {
   410  	msg := "eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g"
   411  
   412  	obj, err := ParseSigned(msg)
   413  	if err != nil {
   414  		t.Fatal("unable to parse message", msg, err)
   415  	}
   416  	if obj.Signatures[0].Header.Algorithm != "ES512" {
   417  		t.Error("merged header did not contain expected alg value")
   418  	}
   419  	if obj.Signatures[0].Protected.Algorithm != "ES512" {
   420  		t.Error("protected header did not contain expected alg value")
   421  	}
   422  	if obj.Signatures[0].Unprotected.Algorithm != "" {
   423  		t.Error("unprotected header contained an alg value")
   424  	}
   425  }
   426  
   427  func TestHeaderFieldsFull(t *testing.T) {
   428  	msg := `{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ","protected":"eyJhbGciOiJFUzUxMiJ9","header":{"custom":"test"},"signature":"AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g"}`
   429  
   430  	obj, err := ParseSigned(msg)
   431  	if err != nil {
   432  		t.Fatal("unable to parse message", msg, err)
   433  	}
   434  	if obj.Signatures[0].Header.Algorithm != "ES512" {
   435  		t.Error("merged header did not contain expected alg value")
   436  	}
   437  	if obj.Signatures[0].Protected.Algorithm != "ES512" {
   438  		t.Error("protected header did not contain expected alg value")
   439  	}
   440  	if obj.Signatures[0].Unprotected.Algorithm != "" {
   441  		t.Error("unprotected header contained an alg value")
   442  	}
   443  	if obj.Signatures[0].Unprotected.ExtraHeaders["custom"] != "test" {
   444  		t.Error("unprotected header did not contain custom header value")
   445  	}
   446  }
   447  
   448  // Test vectors generated with nimbus-jose-jwt
   449  func TestErrorMissingPayloadJWS(t *testing.T) {
   450  	_, err := (&rawJSONWebSignature{}).sanitized()
   451  	if err == nil {
   452  		t.Error("was able to parse message with missing payload")
   453  	}
   454  	if !strings.Contains(err.Error(), "missing payload") {
   455  		t.Errorf("unexpected error message, should contain 'missing payload': %s", err)
   456  	}
   457  }
   458  
   459  // Test that a null value in the header doesn't panic
   460  func TestNullHeaderValue(t *testing.T) {
   461  	msg := `{
   462     "payload":
   463      "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
   464       tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
   465     "protected":"eyJhbGciOiJFUzI1NiIsIm5vbmNlIjpudWxsfQ",
   466     "header":
   467      {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
   468     "signature":
   469      "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
   470       lSApmWQxfKTUJqPP3-Kg6NU1Q"
   471    }`
   472  
   473  	defer func() {
   474  		if r := recover(); r != nil {
   475  			t.Errorf("ParseSigned panic'd when parsing a message with a null protected header value")
   476  		}
   477  	}()
   478  	ParseSigned(msg)
   479  }
   480  
   481  // Test for bug:
   482  // https://github.com/go-jose/go-jose/issues/157
   483  func TestEmbedJWKBug(t *testing.T) {
   484  	signerKey := SigningKey{
   485  		Key: &JSONWebKey{
   486  			Key:   rsaTestKey,
   487  			KeyID: "rsa-test-key",
   488  		},
   489  		Algorithm: RS256,
   490  	}
   491  
   492  	signer, err := NewSigner(signerKey, &SignerOptions{EmbedJWK: true})
   493  	if err != nil {
   494  		t.Fatal(err)
   495  	}
   496  
   497  	signerNoEmbed, err := NewSigner(signerKey, &SignerOptions{EmbedJWK: false})
   498  	if err != nil {
   499  		t.Fatal(err)
   500  	}
   501  
   502  	jws, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
   503  	if err != nil {
   504  		t.Fatal(err)
   505  	}
   506  
   507  	jwsNoEmbed, err := signerNoEmbed.Sign([]byte("Lorem ipsum dolor sit amet"))
   508  	if err != nil {
   509  		t.Fatal(err)
   510  	}
   511  
   512  	// This used to panic with:
   513  	// json: error calling MarshalJSON for type *jose.JSONWebKey: go-jose/go-jose: unknown key type '%!s(<nil>)'
   514  	output := jws.FullSerialize()
   515  	outputNoEmbed := jwsNoEmbed.FullSerialize()
   516  
   517  	// Expected output with embed set to true is a JWS with the public JWK embedded, with kid header empty.
   518  	// Expected output with embed set to false is that we set the kid header for key identification instead.
   519  	parsed, err := ParseSigned(output)
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  
   524  	parsedNoEmbed, err := ParseSigned(outputNoEmbed)
   525  	if err != nil {
   526  		t.Fatal(err)
   527  	}
   528  
   529  	if parsed.Signatures[0].Header.KeyID != "" {
   530  		t.Error("expected kid field in protected header to be empty")
   531  	}
   532  	if parsed.Signatures[0].Header.JSONWebKey.KeyID != "rsa-test-key" {
   533  		t.Error("expected rsa-test-key to be kid in embedded JWK in protected header")
   534  	}
   535  	if parsedNoEmbed.Signatures[0].Header.KeyID != "rsa-test-key" {
   536  		t.Error("expected kid field in protected header to be rsa-test-key")
   537  	}
   538  	if parsedNoEmbed.Signatures[0].Header.JSONWebKey != nil {
   539  		t.Error("expected no embedded JWK to be present")
   540  	}
   541  }
   542  
   543  func TestJWSWithCertificateChain(t *testing.T) {
   544  	signerKey := SigningKey{
   545  		Key:       rsaTestKey,
   546  		Algorithm: RS256,
   547  	}
   548  
   549  	certs := []string{
   550  		// CN=TrustedSigner, signed by IntermediateCA
   551  		"MIIDOjCCAiKgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwGTEXMBUGA1UEAwwOSW50ZXJtZWRpYXRlQ0EwHhcNMjAxMDA0MjMzNDA3WhcNNDAxMDA0MjMzNDA3WjAYMRYwFAYDVQQDDA1UcnVzdGVkU2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAswje1TAIK6aBvvVbuf3bq0emTEDXsTnovRv7HArauy0Lc72Gai8tuc1WVAmw8byxqaNHnHTfIT66UxPBcktr59A9KW2NqNXtNlhVgyIcYFEBFgmKjItmHG2BTw8HIvUnrcneRY9w/gE74f+7BPl0WUE2jsKkf8cIvZso5osGoBwVRN5YP0aWersaXVpA+hVUbMuwUnAvLdvuSvXDtL6SDdisHV9rhZH2jRAj6BzmC4mAD9BATeFFqC1Nt+bo1d7TUNk/FEbjyzs6g9QCUsTTL2RoPFvdQYjnYoIl4tVClUGipeEXb3e84k/ZEUDC04ENCONM/BsQEHBcR0eylViD7QIDAQABo4GMMIGJMB0GA1UdDgQWBBQ5GmxMDIgf21y8SDTSMy2/bZjcLjAfBgNVHSMEGDAWgBTZZOBbEfV70Ocm9RIM16yhAw4SyjAOBgNVHQ8BAf8EBAMCA7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBgGA1UdEQQRMA+CDVRydXN0ZWRTaWduZXIwDQYJKoZIhvcNAQELBQADggEBAHS3KHVV/8H5eH2ZsDRsXyZkdqQlArlWCNK5I1xXW3jxnmAkrMu/Boin82foKLX7sNV33pdec8QMZMY3sTqr8OR+4haehYT9Dw6K4FEBtwRcuR08KducwnQO+kEeixkYtGpRX81hzLLdPHup9u+70WRsiSbgrYq9mV9bec+0uylbfh7ervNncIMTQvjZVkMnELrxe5l31UsZddHs2bzPbdlHuEhNmYxgzCXcFmpvv/WuuNiqVruQKzLYgR+F+eeE5UtmtE/gEBtPFHyLqQCoDcPqRY6B0VqNdcobPz4VOV8Fbf1HOzYEn7TdVglw6PTb5AXQ7/wnRss6SUofg6wzdzY=",
   552  		// CN=IntermediateCA, signed by TrustedCA
   553  		"MIIEDzCCAfegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJVHJ1c3RlZENBMB4XDTIwMTAwNDIzMDMzM1oXDTQwMTAwNDIzMDMzM1owGTEXMBUGA1UEAwwOSW50ZXJtZWRpYXRlQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDiKADoUoaNvD4yCLPySuPR1saLWHNRlt2nqbd7smwB1quNKnKwAKKnLyaBUHICFrQjCTA7IF7KUndVU0vutMFzn6hKuliZMYbwDQgx6x8u34m8Ar8cAg/AJPgT5Kk6Ds8soUaTzRG/GXVjGll0ArjRp97LmOW1Tc53R4YJji6eTThgb4Al6XDou2AeEMNYC46yqafwzOvHOnzSQwy8IwdcFjNKry15pvutIK3UhZscAmfbNEN5ou3miWcz3PuVGORxKAqlA4mYoJWE2AF52fgNTYcTFCDdiThaFSBzgqEgFoDzzROhf1B+/bSJ4gULK9YQxpXVmt8/tlvXjNygDj1LAgMBAAGjZjBkMB0GA1UdDgQWBBTZZOBbEfV70Ocm9RIM16yhAw4SyjAfBgNVHSMEGDAWgBTJ8bqL9u+G1ykEpl9uakSgZGq3JDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEADfEtLh3YDabrTsx+KmJ1f8ybwdltgI3gPiubd5RcYcoO3Pd33/INJDMkJYfLCrSDLI5Y94szOUhkP/rSwrUgJErnPSPUEW11GgA230d7vjc3bFJO/bPb2ZAwm/eC7dMMyyDH/2Wty7h7SOuXXJljZYIvuavJymZxsmkDAu7MtdntHVLr5bruEYvM9IKad9YZSchRP1Q3kIZuTmNvBgLGwrVw/UcOpczajULNNzPUNPDFs9Zo04tx/YF1R1fOGUhif13DMk+6JU7zUXZL3iqOSkxBRrlMQX6nKAQ68cMqO2UsrfXBqH5xm3O9+NxsfN3CkkTcyBcvVFMaMe0670lCh3DcFOMDt2YdlqS5tEsBn3TdOFKSjv2dVnT2eeXcq5IvuC4nkEXzZDROfQVrnraBhHOiyLAlfwhA1LHZGlJfNZaWRDdXHKV+pIMr2JyOv/hf9aaWzjwyy7FJwn3yrEwHGfBgx0vgKPj6l6N8qxQ6l1XMyANx4ExlpXfffx+CPWV9eeMi4Wh6V9641LesQnlOGgL5R03jQRjaicp3nvzsNElDEgPq0s9PE8s6weFKBz5ykrw/Gg4QWmw6MfwjOX5Fu1oJF9ABoCFD5umvKhpoJkcT8aYM0+E1xiEAx64uWq2b2GCGP4wMEZuqCcE72fiue295ovPkNsbEjTQk/ijWza0=",
   554  	}
   555  
   556  	testCases := []struct {
   557  		// Cert chain to embed in message
   558  		chain []string
   559  		// Intermediates & root certificate to verify against
   560  		intermediates []string
   561  		root          string
   562  		// Should this test case verify?
   563  		success bool
   564  	}{
   565  		{certs, nil, trustedCA, true},
   566  		{certs, []string{intermediateCA}, trustedCA, true},
   567  		{certs[0:1], nil, intermediateCA, true},
   568  		{certs[0:1], nil, trustedCA, false},
   569  		{[]string{}, nil, trustedCA, false},
   570  	}
   571  
   572  	for i, testCase := range testCases {
   573  		signer, err := NewSigner(signerKey, &SignerOptions{
   574  			ExtraHeaders: map[HeaderKey]interface{}{HeaderKey("x5c"): testCase.chain},
   575  		})
   576  		if err != nil {
   577  			t.Fatal(err)
   578  		}
   579  
   580  		signed, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
   581  		if err != nil {
   582  			t.Fatal(err)
   583  		}
   584  
   585  		parsed, err := ParseSigned(signed.FullSerialize())
   586  		if err != nil {
   587  			t.Fatal(err)
   588  		}
   589  
   590  		opts := x509.VerifyOptions{
   591  			DNSName: "TrustedSigner",
   592  			Roots:   x509.NewCertPool(),
   593  		}
   594  
   595  		ok := opts.Roots.AppendCertsFromPEM([]byte(testCase.root))
   596  		if !ok {
   597  			t.Fatal("failed to parse trusted root certificate")
   598  		}
   599  
   600  		if len(testCase.intermediates) > 0 {
   601  			opts.Intermediates = x509.NewCertPool()
   602  			for _, intermediate := range testCase.intermediates {
   603  				ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
   604  				if !ok {
   605  					t.Fatal("failed to parse trusted root certificate")
   606  				}
   607  			}
   608  		}
   609  
   610  		chains, err := parsed.Signatures[0].Protected.Certificates(opts)
   611  		if testCase.success && (len(chains) == 0 || err != nil) {
   612  			t.Fatalf("failed to verify certificate chain for test case %d: %s", i, err)
   613  		}
   614  		if !testCase.success && (len(chains) != 0 && err == nil) {
   615  			t.Fatalf("incorrectly verified certificate chain for test case %d (should fail)", i)
   616  		}
   617  	}
   618  }
   619  
   620  func TestDetachedCompactSerialization(t *testing.T) {
   621  	msg := "eyJhbGciOiJSUzI1NiJ9.JC4wMg.W5tc_EUhxexcvLYEEOckyyvdb__M5DQIVpg6Nmk1XGM"
   622  	exp := "eyJhbGciOiJSUzI1NiJ9..W5tc_EUhxexcvLYEEOckyyvdb__M5DQIVpg6Nmk1XGM"
   623  
   624  	obj, err := ParseSigned(msg)
   625  	if err != nil {
   626  		t.Fatal(err)
   627  	}
   628  
   629  	ser, err := obj.DetachedCompactSerialize()
   630  	if err != nil {
   631  		t.Fatal(err)
   632  	}
   633  
   634  	if ser != exp {
   635  		t.Fatalf("got '%s', expected '%s'", ser, exp)
   636  	}
   637  
   638  	obj, err = ParseDetached(ser, []byte("$.02"))
   639  	if err != nil {
   640  		t.Fatal(err)
   641  	}
   642  
   643  	ser, err = obj.CompactSerialize()
   644  	if err != nil {
   645  		t.Fatal(err)
   646  	}
   647  
   648  	if ser != msg {
   649  		t.Fatalf("got '%s', expected '%s'", ser, msg)
   650  	}
   651  }
   652  
   653  func TestJWSComputeAuthDataBase64(t *testing.T) {
   654  	jws := JSONWebSignature{}
   655  
   656  	_, err := jws.computeAuthData([]byte{0x01}, &Signature{
   657  		original: &rawSignatureInfo{
   658  			Protected: newBuffer([]byte("{!invalid-json}")),
   659  		},
   660  	})
   661  	// Invalid header, should return error
   662  	assert.NotNil(t, err)
   663  
   664  	payload := []byte{0x01}
   665  	encodedPayload := base64.RawURLEncoding.EncodeToString(payload)
   666  
   667  	b64TrueHeader := newBuffer([]byte(`{"alg":"RSA-OAEP","enc":"A256GCM","b64":true}`))
   668  	b64FalseHeader := newBuffer([]byte(`{"alg":"RSA-OAEP","enc":"A256GCM","b64":false}`))
   669  
   670  	data, err := jws.computeAuthData(payload, &Signature{
   671  		original: &rawSignatureInfo{
   672  			Protected: b64TrueHeader,
   673  		},
   674  	})
   675  	assert.Nil(t, err)
   676  	// Payload should be b64 encoded
   677  	assert.Len(t, data, len(b64TrueHeader.base64())+len(encodedPayload)+1)
   678  
   679  	data, err = jws.computeAuthData(payload, &Signature{
   680  		original: &rawSignatureInfo{
   681  			Protected: b64FalseHeader,
   682  		},
   683  	})
   684  	assert.Nil(t, err)
   685  	// Payload should *not* be b64 encoded
   686  	assert.Len(t, data, len(b64FalseHeader.base64())+len(payload)+1)
   687  }
   688  

View as plain text