certspotter/tlstypes/signatures.go

135 lines
3.4 KiB
Go

// Copyright (C) 2025 Opsmate, Inc.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License, v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This software is distributed WITHOUT A WARRANTY OF ANY KIND.
// See the Mozilla Public License for details.
package tlstypes
import (
"bytes"
"encoding/json"
"fmt"
"golang.org/x/crypto/cryptobyte"
)
type HashAlgorithm uint8
const (
SHA224 HashAlgorithm = 3
SHA256 HashAlgorithm = 4
SHA384 HashAlgorithm = 5
SHA512 HashAlgorithm = 6
)
type SignatureAlgorithm uint8
const (
RSA SignatureAlgorithm = 1
ECDSA SignatureAlgorithm = 3
)
type SignatureAndHashAlgorithm struct {
Hash HashAlgorithm
Signature SignatureAlgorithm
}
type DigitallySigned struct {
Algorithm SignatureAndHashAlgorithm
Signature []byte
}
func (v HashAlgorithm) Marshal(b *cryptobyte.Builder) error {
b.AddUint8(uint8(v))
return nil
}
func (v *HashAlgorithm) Unmarshal(s *cryptobyte.String) bool {
return s.ReadUint8((*uint8)(v))
}
func (v SignatureAlgorithm) Marshal(b *cryptobyte.Builder) error {
b.AddUint8(uint8(v))
return nil
}
func (v *SignatureAlgorithm) Unmarshal(s *cryptobyte.String) bool {
return s.ReadUint8((*uint8)(v))
}
func (v SignatureAndHashAlgorithm) Marshal(b *cryptobyte.Builder) error {
b.AddValue(v.Hash)
b.AddValue(v.Signature)
return nil
}
func (v *SignatureAndHashAlgorithm) Unmarshal(s *cryptobyte.String) bool {
return v.Hash.Unmarshal(s) && v.Signature.Unmarshal(s)
}
func (v DigitallySigned) Marshal(b *cryptobyte.Builder) error {
b.AddValue(v.Algorithm)
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(v.Signature) })
return nil
}
func (v *DigitallySigned) Unmarshal(s *cryptobyte.String) bool {
return v.Algorithm.Unmarshal(s) && s.ReadUint16LengthPrefixed((*cryptobyte.String)(&v.Signature))
}
func (v DigitallySigned) Bytes() []byte {
b := cryptobyte.NewBuilder(make([]byte, 0, 4+len(v.Signature)))
b.AddValue(v)
return b.BytesOrPanic()
}
func (v DigitallySigned) MarshalBinary() ([]byte, error) {
b := cryptobyte.NewBuilder(make([]byte, 0, 4+len(v.Signature)))
b.AddValue(v)
return b.Bytes()
}
func (v *DigitallySigned) UnmarshalBinary(data []byte) error {
str := cryptobyte.String(bytes.Clone(data))
if !v.Unmarshal(&str) {
return fmt.Errorf("DigitallySigned bytes are malformed")
}
if !str.Empty() {
return fmt.Errorf("trailing bytes after DigitallySigned")
}
return nil
}
func (v DigitallySigned) MarshalJSON() ([]byte, error) {
b := cryptobyte.NewBuilder(make([]byte, 0, 4+len(v.Signature)))
b.AddValue(v)
if bytes, err := b.Bytes(); err != nil {
return nil, err
} else {
return json.Marshal(bytes)
}
}
func (v *DigitallySigned) UnmarshalJSON(data []byte) error {
str := new(cryptobyte.String)
if err := json.Unmarshal(data, (*[]byte)(str)); err != nil {
return fmt.Errorf("unable to unmarshal DigitallySigned JSON: %w", err)
}
if !v.Unmarshal(str) {
return fmt.Errorf("DigitallySigned bytes are malformed")
}
if !str.Empty() {
return fmt.Errorf("trailing bytes after DigitallySigned")
}
return nil
}
func ParseDigitallySigned(bytes []byte) (*DigitallySigned, error) {
ds := new(DigitallySigned)
str := cryptobyte.String(bytes)
if !ds.Unmarshal(&str) {
return nil, fmt.Errorf("DigitallySigned bytes are malformed")
}
if !str.Empty() {
return nil, fmt.Errorf("trailing bytes after DigitallySigned")
}
return ds, nil
}