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