github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/caam/ecdsa.go (about)

     1  // NXP Cryptographic Acceleration and Assurance Module (CAAM) driver
     2  // https://github.com/usbarmory/tamago
     3  //
     4  // Copyright (c) WithSecure Corporation
     5  // https://foundry.withsecure.com
     6  //
     7  // Use of this source code is governed by the license
     8  // that can be found in the LICENSE file.
     9  
    10  package caam
    11  
    12  import (
    13  	"bytes"
    14  	"crypto/ecdsa"
    15  	"encoding/binary"
    16  	"errors"
    17  	"fmt"
    18  	"math/big"
    19  
    20  	"github.com/usbarmory/tamago/bits"
    21  	"github.com/usbarmory/tamago/dma"
    22  )
    23  
    24  // p451, Table 8-112, IMX7DSSRM
    25  const (
    26  	DSA_SIG_PDB_PD     = 22
    27  	DSA_SIG_PDB_ECDSEL = 7
    28  )
    29  
    30  // p443, Table 8-101, IMX7DSSRM
    31  const (
    32  	// Table 8-101
    33  	ECDSEL_P256   = 0x02
    34  	ECDSEL_P256K1 = 0x20
    35  )
    36  
    37  // SignPDB represents an ECDSA sign protocol data block (PDB).
    38  type SignPDB struct {
    39  	// size of the group
    40  	n int
    41  	// elliptic curve domain selection
    42  	ecdsel int
    43  	// private key
    44  	s uint
    45  	// message hash
    46  	f uint
    47  	// signature buffer
    48  	c uint
    49  	// signature buffer (2nd part, n length)
    50  	d uint
    51  
    52  	// DMA buffer
    53  	sig []byte
    54  }
    55  
    56  // Init initializes a PDB for ECDSA signing.
    57  func (pdb *SignPDB) Init(priv *ecdsa.PrivateKey) (err error) {
    58  	name := priv.PublicKey.Curve.Params().Name
    59  
    60  	switch name {
    61  	case "P-256":
    62  		pdb.n = 32
    63  		pdb.ecdsel = ECDSEL_P256
    64  	case "P-256k1":
    65  		pdb.n = 32
    66  		pdb.ecdsel = ECDSEL_P256K1
    67  	default:
    68  		return fmt.Errorf("unsupported curve %s", name)
    69  	}
    70  
    71  	pdb.n = priv.PublicKey.Curve.Params().BitSize / 8
    72  
    73  	pdb.s = dma.Alloc(make([]byte, pdb.n), 4)
    74  	dma.Write(pdb.s, 0, priv.D.Bytes())
    75  
    76  	pdb.f, _ = dma.Reserve(pdb.n, 4)
    77  
    78  	pdb.c, pdb.sig = dma.Reserve(pdb.n*2, 4)
    79  	pdb.d = pdb.c + uint(pdb.n)
    80  
    81  	return
    82  }
    83  
    84  func (pdb *SignPDB) Hash(hash []byte) {
    85  	dma.Write(pdb.f, 0, hash[0:pdb.n])
    86  }
    87  
    88  // Bytes converts the PDB to byte array format.
    89  func (pdb *SignPDB) Bytes() []byte {
    90  	var word0 uint32
    91  
    92  	// p451, Table 8-112, IMX7DSSRM
    93  
    94  	bits.Set(&word0, DSA_SIG_PDB_PD)
    95  	bits.SetN(&word0, DSA_SIG_PDB_ECDSEL, 0x7f, uint32(pdb.ecdsel))
    96  
    97  	buf := new(bytes.Buffer)
    98  	binary.Write(buf, binary.LittleEndian, uint32(word0))
    99  	binary.Write(buf, binary.LittleEndian, uint32(pdb.s))
   100  	binary.Write(buf, binary.LittleEndian, uint32(pdb.f))
   101  	binary.Write(buf, binary.LittleEndian, uint32(pdb.c))
   102  	binary.Write(buf, binary.LittleEndian, uint32(pdb.d))
   103  
   104  	return buf.Bytes()
   105  }
   106  
   107  // Free frees the memory allocated by the PDB.
   108  func (pdb *SignPDB) Free() {
   109  	dma.Release(pdb.c)
   110  	dma.Release(pdb.f)
   111  	dma.Free(pdb.s)
   112  }
   113  
   114  // Sign signs a hash (which should be the result of hashing a larger message)
   115  // using the private key, priv. If the hash is longer than the bit-length of
   116  // the private key's curve order, the hash will be truncated to that length. It
   117  // returns the signature as a pair of integers.
   118  //
   119  // A previously initialized sign protocol data block (see SignPDB.Init()) may
   120  // be passed to cache private key initialization, in this case priv is ignored.
   121  func (hw *CAAM) Sign(priv *ecdsa.PrivateKey, hash []byte, pdb *SignPDB) (r, s *big.Int, err error) {
   122  	if pdb == nil {
   123  		pdb = &SignPDB{}
   124  		defer pdb.Free()
   125  
   126  		if err = pdb.Init(priv); err != nil {
   127  			return
   128  		}
   129  	} else if pdb.n == 0 {
   130  		return nil, nil, errors.New("pdb is not initialized")
   131  	}
   132  
   133  	pdb.Hash(hash)
   134  	jd := pdb.Bytes()
   135  
   136  	var info uint32
   137  	bits.Set(&info, PROTINFO_ECC)
   138  	bits.SetTo(&info, PROTINFO_SIGN_NO_TEQ, hw.DisableTimingEqualization)
   139  
   140  	op := Operation{}
   141  	op.SetDefaults()
   142  	op.OpType(OPTYPE_PROT_UNI)
   143  	op.Protocol(PROTID_ECDSA_SIGN, info)
   144  
   145  	hdr := &Header{}
   146  	hdr.SetDefaults()
   147  	hdr.StartIndex(1 + len(jd)/4)
   148  
   149  	jd = append(jd, op.Bytes()...)
   150  	hdr.Length(1 + len(jd)/4)
   151  
   152  	if err = hw.job(hdr, jd); err != nil {
   153  		return
   154  	}
   155  
   156  	r = &big.Int{}
   157  	r.SetBytes(pdb.sig[0:pdb.n])
   158  
   159  	s = &big.Int{}
   160  	s.SetBytes(pdb.sig[pdb.n:])
   161  
   162  	return
   163  }