key_package_crypto.mx raw

   1  package mls
   2  
   3  // MLS key package crypto operations (RFC 9420 ยง10).
   4  
   5  var (
   6  	errKeyPackageVersionMismatch error
   7  	errKeyPackageSuiteMismatch   error
   8  	errKeyPackageBadSource       error
   9  	errKeyPackageBadSignature    error
  10  	errKeyPackageKeysMatch       error
  11  )
  12  
  13  func (pkg *KeyPackage) sign(signerPriv []byte) (err error) {
  14  	var w Writer
  15  	pkg.marshalTBS(&w)
  16  	rawTBS, err := w.bytes()
  17  	if err != nil {
  18  		return err
  19  	}
  20  	sig, err := pkg.cipherSuite.signWithLabel(signerPriv, []byte("KeyPackageTBS"), rawTBS)
  21  	if err != nil {
  22  		return err
  23  	}
  24  	pkg.signature = sig
  25  	return nil
  26  }
  27  
  28  func (pkg *KeyPackage) verifySignature() (ok bool) {
  29  	var w Writer
  30  	pkg.marshalTBS(&w)
  31  	rawTBS, err := w.bytes()
  32  	if err != nil {
  33  		return false
  34  	}
  35  	return pkg.cipherSuite.verifyWithLabel(pkg.leafNode.signatureKey, []byte("KeyPackageTBS"), rawTBS, pkg.signature)
  36  }
  37  
  38  func (pkg *KeyPackage) verify(ctx *groupContext) (err error) {
  39  	if pkg.version != ctx.version {
  40  		return errKeyPackageVersionMismatch
  41  	}
  42  	if pkg.cipherSuite != ctx.cipherSuite {
  43  		return errKeyPackageSuiteMismatch
  44  	}
  45  	if pkg.leafNode.leafNodeSource != leafNodeSourceKeyPackage {
  46  		return errKeyPackageBadSource
  47  	}
  48  	if !pkg.verifySignature() {
  49  		return errKeyPackageBadSignature
  50  	}
  51  	if bytesEqual(pkg.leafNode.encryptionKey, pkg.initKey) {
  52  		return errKeyPackageKeysMatch
  53  	}
  54  	return nil
  55  }
  56  
  57  func (pkg *KeyPackage) GenerateRef() (v []byte, err2 error) {
  58  	var w Writer
  59  	pkg.marshal(&w)
  60  	raw, err := w.bytes()
  61  	if err != nil {
  62  		return nil, err
  63  	}
  64  	h, err := pkg.cipherSuite.refHash([]byte("MLS 1.0 KeyPackage Reference"), raw)
  65  	if err != nil {
  66  		return nil, err
  67  	}
  68  	return h, nil
  69  }
  70  
  71  // GenerateKeyPairPackage creates a new key pair package for suite 0x0003.
  72  // nowUnix is the current time as Unix seconds (caller provides from DOM/SW context).
  73  func GenerateKeyPairPackage(cs CipherSuite, credential *Credential, nowUnix int64) (p *KeyPairPackage, err error) {
  74  	return GenerateKeyPairPackageWithOptions(cs, credential, nil, nowUnix)
  75  }
  76  
  77  // GenerateKeyPairPackageWithOptions creates a key pair package with options.
  78  func GenerateKeyPairPackageWithOptions(cs CipherSuite, credential *Credential, opts *KeyPackageOptions, nowUnix int64) (p *KeyPairPackage, err2 error) {
  79  	initPub, initPriv, err := cs.generateEncryptionKeyPair()
  80  	if err != nil {
  81  		return nil, err
  82  	}
  83  	encPub, encPriv, err := cs.generateEncryptionKeyPair()
  84  	if err != nil {
  85  		return nil, err
  86  	}
  87  	sigPub, sigPriv, err := cs.generateSignatureKeyPair()
  88  	if err != nil {
  89  		return nil, err
  90  	}
  91  
  92  	var capExts []extensionType
  93  	var leafExts []extension
  94  	var kpExts []extension
  95  	if opts != nil {
  96  		capExts = opts.CapabilityExtensions
  97  		leafExts = opts.LeafExtensions
  98  		kpExts = opts.KeyPackageExtensions
  99  	}
 100  	if capExts == nil {
 101  		capExts = []extensionType{extensionTypeRatchetTree}
 102  	}
 103  
 104  	// Lifetime: now - 1h to now + 84 days
 105  	notBefore := nowUnix - 3600
 106  	notAfter := nowUnix + 84*24*3600
 107  
 108  	keyPkg := KeyPackage{
 109  		version:     protocolVersionMLS10,
 110  		cipherSuite: cs,
 111  		initKey:     initPub,
 112  		leafNode: leafNode{
 113  			encryptionKey:  encPub,
 114  			signatureKey:   sigPub,
 115  			leafNodeSource: leafNodeSourceKeyPackage,
 116  			credential:     *credential,
 117  			capabilities: capabilities{
 118  				versions:     []protocolVersion{protocolVersionMLS10},
 119  				cipherSuites: []CipherSuite{cs},
 120  				extensions:   capExts,
 121  				proposals:    []proposalType{proposalTypeAdd, proposalTypeUpdate, proposalTypeRemove},
 122  				credentials:  []credentialType{credentialTypeBasic},
 123  			},
 124  			lifetime:   &lifetime{notBefore: uint64(notBefore), notAfter: uint64(notAfter)},
 125  			extensions: leafExts,
 126  		},
 127  		extensions: kpExts,
 128  	}
 129  
 130  	if e := keyPkg.leafNode.sign(cs, nil, 0, sigPriv); e != nil {
 131  		return nil, e
 132  	}
 133  	if e := keyPkg.sign(sigPriv); e != nil {
 134  		return nil, e
 135  	}
 136  
 137  	return &KeyPairPackage{
 138  		Public: keyPkg,
 139  		Private: PrivateKeyPackage{
 140  			InitKey:       initPriv,
 141  			EncryptionKey: encPriv,
 142  			SignatureKey:  sigPriv,
 143  		},
 144  	}, nil
 145  }
 146