func parseCompact(buf []byte) (*Message, error) { debug.Printf("Parse(Compact): buf = '%s'", buf) parts := bytes.Split(buf, []byte{'.'}) if len(parts) != 5 { return nil, ErrInvalidCompactPartsCount } hdrbuf := buffer.Buffer{} if err := hdrbuf.Base64Decode(parts[0]); err != nil { return nil, err } debug.Printf("hdrbuf = %s", hdrbuf) hdr := NewHeader() if err := json.Unmarshal(hdrbuf, hdr); err != nil { return nil, err } // We need the protected header to contain the content encryption // algorithm. XXX probably other headers need to go there too protected := NewEncodedHeader() protected.ContentEncryption = hdr.ContentEncryption hdr.ContentEncryption = "" enckeybuf := buffer.Buffer{} if err := enckeybuf.Base64Decode(parts[1]); err != nil { return nil, err } ivbuf := buffer.Buffer{} if err := ivbuf.Base64Decode(parts[2]); err != nil { return nil, err } ctbuf := buffer.Buffer{} if err := ctbuf.Base64Decode(parts[3]); err != nil { return nil, err } tagbuf := buffer.Buffer{} if err := tagbuf.Base64Decode(parts[4]); err != nil { return nil, err } m := NewMessage() m.AuthenticatedData.SetBytes(hdrbuf.Bytes()) m.ProtectedHeader = protected m.Tag = tagbuf m.CipherText = ctbuf m.InitializationVector = ivbuf m.Recipients = []Recipient{ Recipient{ Header: hdr, EncryptedKey: enckeybuf, }, } return m, nil }
// UnmarshalJSON parses the JSON buffer into a Header func (e *EncodedHeader) UnmarshalJSON(buf []byte) error { b := buffer.Buffer{} // base646 json string -> json object representation of header if err := json.Unmarshal(buf, &b); err != nil { return err } if err := json.Unmarshal(b.Bytes(), &e.Header); err != nil { return err } return nil }
// TestEncode_HS256Compact tests that https://tools.ietf.org/html/rfc7515#appendix-A.1 works func TestEncode_HS256Compact(t *testing.T) { const hdr = `{"typ":"JWT",` + "\r\n" + ` "alg":"HS256"}` const hmacKey = `AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow` const expected = `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk` hmacKeyDecoded := buffer.Buffer{} hmacKeyDecoded.Base64Decode([]byte(hmacKey)) sign, err := NewHmacSign(jwa.HS256, hmacKeyDecoded.Bytes()) if !assert.NoError(t, err, "HmacSign created successfully") { return } hdrbuf, err := buffer.Buffer(hdr).Base64Encode() if !assert.NoError(t, err, "base64 encode successful") { return } payload, err := buffer.Buffer(examplePayload).Base64Encode() if !assert.NoError(t, err, "base64 encode successful") { return } signingInput := bytes.Join( [][]byte{ hdrbuf, payload, }, []byte{'.'}, ) signature, err := sign.PayloadSign(signingInput) if !assert.NoError(t, err, "PayloadSign is successful") { return } sigbuf, err := buffer.Buffer(signature).Base64Encode() if !assert.NoError(t, err, "base64 encode successful") { return } encoded := bytes.Join( [][]byte{ signingInput, sigbuf, }, []byte{'.'}, ) if !assert.Equal(t, expected, string(encoded), "generated compact serialization should match") { return } msg, err := Parse(encoded) if !assert.NoError(t, err, "Parsing compact encoded serialization succeeds") { return } hdrs := msg.Signatures[0].MergedHeaders() if !assert.Equal(t, hdrs.Algorithm(), jwa.HS256, "Algorithm in header matches") { return } v, err := NewHmacVerify(jwa.HS256, hmacKeyDecoded.Bytes()) if !assert.NoError(t, err, "HmacVerify created") { return } if !assert.NoError(t, v.Verify(msg), "Verify succeeds") { return } }