xref: /aosp_15_r20/external/libese/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMCose.java (revision 5c4dab75aa57366379dce576b1a9e082a44e2b3a)
1 /*
2  * Copyright(C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.javacard.keymaster;
18 
19 import javacard.framework.ISO7816;
20 import javacard.framework.ISOException;
21 
22 /**
23  * This class constructs the Cose messages like CoseKey, CoseMac0, MacStructure, CoseSign1,
24  * SignStructure, CoseEncrypt, EncryptStructure and ReceipientStructures.
25  */
26 public class KMCose {
27 
28   // COSE SIGN1
29   public static final byte COSE_SIGN1_ENTRY_COUNT = 4;
30   public static final byte COSE_SIGN1_PROTECTED_PARAMS_OFFSET = 0;
31   public static final byte COSE_SIGN1_PAYLOAD_OFFSET = 2;
32   public static final byte COSE_SIGN1_SIGNATURE_OFFSET = 3;
33   // COSE MAC0
34   public static final byte COSE_MAC0_ENTRY_COUNT = 4;
35   public static final byte COSE_MAC0_PROTECTED_PARAMS_OFFSET = 0;
36   public static final byte COSE_MAC0_PAYLOAD_OFFSET = 2;
37   public static final byte COSE_MAC0_TAG_OFFSET = 3;
38   // COSE ENCRYPT
39   public static final byte COSE_ENCRYPT_ENTRY_COUNT = 4;
40   public static final byte COSE_ENCRYPT_STRUCTURE_ENTRY_COUNT = 3;
41   public static final byte COSE_ENCRYPT_RECIPIENT_ENTRY_COUNT = 3;
42 
43   // COSE Labels
44   public static final byte COSE_LABEL_ALGORITHM = 1;
45   public static final byte COSE_LABEL_KEYID = 4;
46   public static final byte COSE_LABEL_IV = 5;
47   public static final byte COSE_LABEL_COSE_KEY = (byte) 0xFF; // -1
48 
49   // COSE Algorithms
50   public static final byte COSE_ALG_AES_GCM_256 = 3; // AES-GCM mode w/ 256-bit key, 128-bit tag.
51   public static final byte COSE_ALG_HMAC_256 = 5; // HMAC w/ SHA-256
52   public static final byte COSE_ALG_ES256 = (byte) 0xF9; // ECDSA w/ SHA-256; -7
53   public static final byte COSE_ALG_ECDH_ES_HKDF_256 = (byte) 0xE7; // ECDH-EC+HKDF-256; -25
54 
55   // COSE P256 EC Curve
56   public static final byte COSE_ECCURVE_256 = 1;
57 
58   // COSE key types
59   public static final byte COSE_KEY_TYPE_EC2 = 2;
60   public static final byte COSE_KEY_TYPE_SYMMETRIC_KEY = 4;
61 
62   // COSE Key Operations
63   public static final byte COSE_KEY_OP_SIGN = 1;
64   public static final byte COSE_KEY_OP_VERIFY = 2;
65   public static final byte COSE_KEY_OP_ENCRYPT = 3;
66   public static final byte COSE_KEY_OP_DECRYPT = 4;
67 
68   // AES GCM
69   public static final short AES_GCM_KEY_SIZE_BITS = 256;
70   // Cose key parameters.
71   public static final short COSE_KEY_KEY_TYPE = 1;
72   public static final short COSE_KEY_KEY_ID = 2;
73   public static final short COSE_KEY_ALGORITHM = 3;
74   public static final short COSE_KEY_CURVE = -1;
75   public static final short COSE_KEY_PUBKEY_X = -2;
76   public static final short COSE_KEY_PUBKEY_Y = -3;
77   public static final short COSE_KEY_PRIV_KEY = -4;
78   public static final byte[] COSE_TEST_KEY = {
79     (byte) 0xFF, (byte) 0xFE, (byte) 0xEE, (byte) 0x90
80   }; // -70000
81   public static final byte COSE_KEY_MAX_SIZE = 4;
82 
83   // kdfcontext strings
84   public static final byte[] client = {0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74};
85   public static final byte[] server = {0x73, 0x65, 0x72, 0x76, 0x65, 0x72};
86   // Context strings
87   public static final byte[] MAC_CONTEXT = {0x4d, 0x41, 0x43, 0x30}; // MAC0
88   public static final byte[] SIGNATURE1_CONTEXT = {
89     0x53, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x31
90   }; // Signature1
91   public static final byte[] ENCRYPT_CONTEXT = {
92     0x45, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74
93   }; // Encrypt
94   // Certificate payload supported keys
95   public static final byte ISSUER = (byte) 0x01;
96   public static final byte SUBJECT = (byte) 0x02;
97   public static final byte[] SUBJECT_PUBLIC_KEY = {
98     (byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA8
99   };
100   public static final byte[] KEY_USAGE = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA7};
101   // text strings
102   public static final byte[] TEST_ISSUER_NAME = {
103     (byte) 0x49, 0x73, 0x73, 0x75, 0x65, 0x72
104   }; // "Issuer"
105   public static final byte[] TEST_SUBJECT_NAME = {
106     0x53, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74
107   }; // "Subject"
108   public static final byte[] KEY_USAGE_SIGN = {0x20}; // Key usage sign
109 
110   public static final short[] COSE_KEY_LABELS = {
111     KMCose.COSE_KEY_KEY_TYPE,
112     KMCose.COSE_KEY_KEY_ID,
113     KMCose.COSE_KEY_ALGORITHM,
114     KMCose.COSE_KEY_CURVE,
115     KMCose.COSE_KEY_PUBKEY_X,
116     KMCose.COSE_KEY_PUBKEY_Y,
117     KMCose.COSE_KEY_PRIV_KEY
118   };
119   public static final short[] COSE_HEADER_LABELS = {
120     KMCose.COSE_LABEL_ALGORITHM,
121     KMCose.COSE_LABEL_KEYID,
122     KMCose.COSE_LABEL_IV,
123     KMCose.COSE_LABEL_COSE_KEY
124   };
125 
126   /**
127    * Constructs the Cose MAC structure.
128    *
129    * @param protectedHeader Bstr pointer which holds the protected header.
130    * @param extAad Bstr pointer which holds the external Aad.
131    * @param payload Bstr pointer which holds the payload of the MAC structure.
132    * @return KMArray instance of MAC structure.
133    */
constructCoseMacStructure( short protectedHeader, short extAad, short payload)134   public static short constructCoseMacStructure(
135       short protectedHeader, short extAad, short payload) {
136     // Create MAC Structure and compute HMAC as per https://tools.ietf.org/html/rfc8152#section-6.3
137     //    MAC_structure = [
138     //        context : "MAC" / "MAC0",
139     //        protected : empty_or_serialized_map,
140     //        external_aad : bstr,
141     //        payload : bstr
142     //   ]
143     short arrPtr = KMArray.instance(KMCose.COSE_MAC0_ENTRY_COUNT);
144     // 1 - Context
145     KMArray.cast(arrPtr)
146         .add(
147             (short) 0,
148             KMTextString.instance(
149                 KMCose.MAC_CONTEXT, (short) 0, (short) KMCose.MAC_CONTEXT.length));
150     // 2 - Protected headers.
151     KMArray.cast(arrPtr).add((short) 1, protectedHeader);
152     // 3 - external aad
153     KMArray.cast(arrPtr).add((short) 2, extAad);
154     // 4 - payload.
155     KMArray.cast(arrPtr).add((short) 3, payload);
156     return arrPtr;
157   }
158 
159   /**
160    * Constructs the COSE_MAC0 object.
161    *
162    * @param protectedHeader Bstr pointer which holds the protected header.
163    * @param unprotectedHeader Bstr pointer which holds the unprotected header.
164    * @param payload Bstr pointer which holds the payload of the MAC structure.
165    * @param tag Bstr pointer which holds the tag value.
166    * @return KMArray instance of COSE_MAC0 object.
167    */
constructCoseMac0( short protectedHeader, short unprotectedHeader, short payload, short tag)168   public static short constructCoseMac0(
169       short protectedHeader, short unprotectedHeader, short payload, short tag) {
170     // Construct Cose_MAC0
171     //   COSE_Mac0 = [
172     //      protectedHeader,
173     //      unprotectedHeader,
174     //      payload : bstr / nil,
175     //      tag : bstr,
176     //   ]
177     short arrPtr = KMArray.instance(KMCose.COSE_MAC0_ENTRY_COUNT);
178     // 1 - protected headers
179     KMArray.cast(arrPtr).add((short) 0, protectedHeader);
180     // 2 - unprotected headers
181     KMArray.cast(arrPtr).add((short) 1, unprotectedHeader);
182     // 2 - payload
183     KMArray.cast(arrPtr).add((short) 2, payload);
184     // 3 - tag
185     KMArray.cast(arrPtr).add((short) 3, tag);
186     // Do encode.
187     return arrPtr;
188   }
189 
190   /**
191    * Constructs the COSE_Signature structure.
192    *
193    * @param protectedHeader Bstr pointer which holds the protected header.
194    * @param extAad Bstr pointer which holds the aad.
195    * @param payload Bstr pointer which holds the payload.
196    * @return KMArray instance of COSE_Signature object.
197    */
constructCoseSignStructure( short protectedHeader, short extAad, short payload)198   public static short constructCoseSignStructure(
199       short protectedHeader, short extAad, short payload) {
200     // Sig_structure = [
201     //       context : "Signature" / "Signature1" / "CounterSignature",
202     //       body_protected : empty_or_serialized_map,
203     //       ? sign_protected : empty_or_serialized_map,
204     //       external_aad : bstr,
205     //       payload : bstr
206     //   ]
207     short arrPtr = KMArray.instance(KMCose.COSE_SIGN1_ENTRY_COUNT);
208     // 1 - Context
209     KMArray.cast(arrPtr)
210         .add(
211             (short) 0,
212             KMTextString.instance(
213                 KMCose.SIGNATURE1_CONTEXT, (short) 0, (short) KMCose.SIGNATURE1_CONTEXT.length));
214     // 2 - Protected headers.
215     KMArray.cast(arrPtr).add((short) 1, protectedHeader);
216     // 3 - external aad
217     KMArray.cast(arrPtr).add((short) 2, extAad);
218     // 4 - payload.
219     KMArray.cast(arrPtr).add((short) 3, payload);
220     return arrPtr;
221   }
222 
223   /**
224    * Constructs the COSE_Sign1 object.
225    *
226    * @param protectedHeader Bstr pointer which holds the protected header.
227    * @param unProtectedHeader Bstr pointer which holds the unprotected header.
228    * @param payload Bstr pointer which holds the payload.
229    * @param signature Bstr pointer which holds the signature.
230    * @return KMArray instance of COSE_Sign1 object.
231    */
constructCoseSign1( short protectedHeader, short unProtectedHeader, short payload, short signature)232   public static short constructCoseSign1(
233       short protectedHeader, short unProtectedHeader, short payload, short signature) {
234     //   COSE_Sign = [
235     //      protectedHeader,
236     //      unprotectedHeader,
237     //       payload : bstr / nil,
238     //       signatures : [+ COSE_Signature]
239     //   ]
240     short arrPtr = KMArray.instance(KMCose.COSE_SIGN1_ENTRY_COUNT);
241     // 1 - protected headers
242     KMArray.cast(arrPtr).add((short) 0, protectedHeader);
243     // 2 - unprotected headers
244     KMArray.cast(arrPtr).add((short) 1, unProtectedHeader);
245     // 2 - payload
246     KMArray.cast(arrPtr).add((short) 2, payload);
247     // 3 - tag
248     KMArray.cast(arrPtr).add((short) 3, signature);
249     return arrPtr;
250   }
251 
252   /**
253    * Constructs array based on the tag values provided.
254    *
255    * @param tag array of tag values to be constructed.
256    * @param includeTestMode flag which indicates if TEST_COSE_KEY should be included or not.
257    * @return instance of KMArray.
258    */
handleCosePairTags( short[] tag, short[] keyValues, short valueIndex, boolean includeTestMode)259   private static short handleCosePairTags(
260       short[] tag, short[] keyValues, short valueIndex, boolean includeTestMode) {
261     short index = 0;
262     // var is used to calculate the length of the array.
263     short var = 0;
264     short tagLen = (short) tag.length;
265     // var is used to calculate the length of the array.
266     while (index < tagLen) {
267       if (keyValues[index] != KMType.INVALID_VALUE) {
268         keyValues[(short) (index + valueIndex)] =
269             buildCosePairTag((byte) tag[index], keyValues[index]);
270         var++;
271       }
272       index++;
273     }
274     var += includeTestMode ? 1 : 0;
275     short arrPtr = KMArray.instance(var);
276     index = 0;
277     // var is used to index the array.
278     var = 0;
279     while (index < tagLen) {
280       if (keyValues[(short) (index + valueIndex)] != KMType.INVALID_VALUE) {
281         KMArray.cast(arrPtr).add(var++, keyValues[(short) (index + valueIndex)]);
282       }
283       index++;
284     }
285     return arrPtr;
286   }
287 
288   /**
289    * Constructs the COSE_sign1 payload for certificate.
290    *
291    * @param issuer instance of KMCosePairTextStringTag which contains issuer value.
292    * @param subject instance of KMCosePairTextStringTag which contains subject value.
293    * @param subPublicKey instance of KMCosePairByteBlobTag which contains encoded KMCoseKey.
294    * @param keyUsage instance of KMCosePairByteBlobTag which contains key usage value.
295    * @return instance of KMArray.
296    */
constructCoseCertPayload( short issuer, short subject, short subPublicKey, short keyUsage)297   public static short constructCoseCertPayload(
298       short issuer, short subject, short subPublicKey, short keyUsage) {
299     short certPayload = KMArray.instance((short) 4);
300     KMArray.cast(certPayload).add((short) 0, issuer);
301     KMArray.cast(certPayload).add((short) 1, subject);
302     KMArray.cast(certPayload).add((short) 2, subPublicKey);
303     KMArray.cast(certPayload).add((short) 3, keyUsage);
304     certPayload = KMCoseCertPayload.instance(certPayload);
305     KMCoseCertPayload.cast(certPayload).canonicalize();
306     return certPayload;
307   }
308 
309   /**
310    * Construct headers structure. Headers can be part of COSE_Sign1, COSE_Encrypt, COSE_Mac0 and
311    * COSE_Key.
312    *
313    * @param alg instance of either KMNInteger or KMInteger, based on the sign of algorithm value.
314    * @param keyId instance of KMByteBlob which contains the key identifier.
315    * @param iv instance of KMByteblob which contains the iv buffer.
316    * @param ephemeralKey instance of KMCoseKey.
317    * @return instance of KMCoseHeaders.
318    */
constructHeaders( short[] buff, short alg, short keyId, short iv, short ephemeralKey)319   public static short constructHeaders(
320       short[] buff, short alg, short keyId, short iv, short ephemeralKey) {
321     buff[0] = alg;
322     buff[1] = keyId;
323     buff[2] = iv;
324     buff[3] = ephemeralKey;
325     for (short i = 4; i < 8; i++) {
326       buff[i] = KMType.INVALID_VALUE;
327     }
328     short ptr = handleCosePairTags(COSE_HEADER_LABELS, buff, (short) 4, false);
329     ptr = KMCoseHeaders.instance(ptr);
330     KMCoseHeaders.cast(ptr).canonicalize();
331     return ptr;
332   }
333 
334   /**
335    * Construct Recipients structure for COSE_Encrypt message.
336    *
337    * @param protectedHeaders instance of KMByteBlob which contains encoded KMCoseHeaders.
338    * @param unprotectedHeaders instance of KMCoseHeaders.
339    * @param cipherText instance of KMSimple
340    * @return instance of KMArray.
341    */
constructRecipientsStructure( short protectedHeaders, short unprotectedHeaders, short cipherText)342   public static short constructRecipientsStructure(
343       short protectedHeaders, short unprotectedHeaders, short cipherText) {
344     // recipients : [+COSE_recipient]
345     //  COSE_recipient = [
346     //       Headers,
347     //       ciphertext : bstr / nil,
348     //       ? recipients : [+COSE_recipient]
349     //   ]
350     short arrPtr = KMArray.instance(COSE_ENCRYPT_RECIPIENT_ENTRY_COUNT);
351     // 1 - protected headers
352     KMArray.cast(arrPtr).add((short) 0, protectedHeaders);
353     // 2 - unprotected headers
354     KMArray.cast(arrPtr).add((short) 1, unprotectedHeaders);
355     // 2 - payload
356     KMArray.cast(arrPtr).add((short) 2, cipherText);
357 
358     short recipientsArrayPtr = KMArray.instance((short) 1);
359     KMArray.cast(recipientsArrayPtr).add((short) 0, arrPtr);
360     return recipientsArrayPtr;
361   }
362 
363   /**
364    * Construct Encrypt structure required for COSE_Encrypt message.
365    *
366    * @param protectedHeader instance of KMByteBlob which wraps KMCoseHeaders.
367    * @param aad instance of KMByteBlob.
368    * @return instance of KMArray.
369    */
constructCoseEncryptStructure(short protectedHeader, short aad)370   public static short constructCoseEncryptStructure(short protectedHeader, short aad) {
371     //  Enc_structure = [
372     //       context : "Encrypt" / "Encrypt0" / "Enc_Recipient" /
373     //           "Mac_Recipient" / "Rec_Recipient",
374     //       protected : empty_or_serialized_map,
375     //       external_aad : bstr
376     //   ]
377     short arrPtr = KMArray.instance(COSE_ENCRYPT_STRUCTURE_ENTRY_COUNT);
378     // 1 - protected headers
379     KMArray.cast(arrPtr)
380         .add(
381             (short) 0,
382             KMTextString.instance(
383                 KMCose.ENCRYPT_CONTEXT, (short) 0, (short) KMCose.ENCRYPT_CONTEXT.length));
384     // 2 - unprotected headers
385     KMArray.cast(arrPtr).add((short) 1, protectedHeader);
386     // 2 - payload
387     KMArray.cast(arrPtr).add((short) 2, aad);
388     return arrPtr;
389   }
390 
391   /**
392    * Constructs COSE_Encrypt message.
393    *
394    * @param protectedHeader instance of KMByteBlob which wraps KMCoseHeaders.
395    * @param unProtectedHeader instance of KMCoseHeaders.
396    * @param cipherText instance of KMByteBlob containing the cipher text.
397    * @param recipients instance of KMArray containing the recipients instance
398    * @return instance of KMArray.
399    */
constructCoseEncrypt( short protectedHeader, short unProtectedHeader, short cipherText, short recipients)400   public static short constructCoseEncrypt(
401       short protectedHeader, short unProtectedHeader, short cipherText, short recipients) {
402     // COSE_Encrypt = [
403     //      protectedHeader,
404     //      unprotectedHeader,
405     //       ciphertext : bstr / nil,
406     //       recipients : [+COSE_recipient]
407     //   ]
408     short arrPtr = KMArray.instance(KMCose.COSE_ENCRYPT_ENTRY_COUNT);
409     // 1 - protected headers
410     KMArray.cast(arrPtr).add((short) 0, protectedHeader);
411     // 2 - unprotected headers
412     KMArray.cast(arrPtr).add((short) 1, unProtectedHeader);
413     // 2 - payload
414     KMArray.cast(arrPtr).add((short) 2, cipherText);
415     // 3 - tag
416     KMArray.cast(arrPtr).add((short) 3, recipients);
417     return arrPtr;
418   }
419 
420   /**
421    * Constructs the instance of KMCosePair*Tag.
422    *
423    * @param key value of the key.
424    * @param valuePtr instance of one of KMType.
425    * @return instance of KMCosePair*Value object.
426    */
buildCosePairTag(byte key, short valuePtr)427   public static short buildCosePairTag(byte key, short valuePtr) {
428     short type = KMType.getType(valuePtr);
429     short keyPtr;
430     if (key < 0) {
431       keyPtr = KMNInteger.uint_8(key);
432     } else {
433       keyPtr = KMInteger.uint_8(key);
434     }
435     switch (type) {
436       case KMType.INTEGER_TYPE:
437         return KMCosePairIntegerTag.instance(keyPtr, valuePtr);
438       case KMType.NEG_INTEGER_TYPE:
439         return KMCosePairNegIntegerTag.instance(keyPtr, valuePtr);
440       case KMType.BYTE_BLOB_TYPE:
441         return KMCosePairByteBlobTag.instance(keyPtr, valuePtr);
442       case KMType.TEXT_STRING_TYPE:
443         return KMCosePairTextStringTag.instance(keyPtr, valuePtr);
444       case KMType.COSE_KEY_TYPE:
445         return KMCosePairCoseKeyTag.instance(keyPtr, valuePtr);
446       default:
447         ISOException.throwIt(ISO7816.SW_DATA_INVALID);
448         return 0;
449     }
450   }
451 
452   /**
453    * Constructs a CoseKey with the provided input parameters. Note that construction of the key_ops
454    * label is not needed to be supported. In the KeyMint2.0 specifications: The CoseKey inside
455    * MacedPublicKeys and DiceCertChain does not have key_ops label.
456    *
457    * @param keyType Instance of the identification of the key type.
458    * @param keyId Instance of key identification value.
459    * @param keyAlg Instance of the algorithm that is used with this key.
460    * @param curve Instance of the EC curve that is used with this key.
461    * @param pubKey Buffer containing the public key.
462    * @param pubKeyOff Start offset of the buffer.
463    * @param pubKeyLen Length of the public key.
464    * @param privKeyPtr Instance of the private key.
465    * @param testMode Represents if key is used in test mode or production mode.
466    * @return Instance of the CoseKey structure.
467    */
constructCoseKey( short[] buff, short keyType, short keyId, short keyAlg, short curve, byte[] pubKey, short pubKeyOff, short pubKeyLen, short privKeyPtr, boolean testMode)468   public static short constructCoseKey(
469       short[] buff,
470       short keyType,
471       short keyId,
472       short keyAlg,
473       short curve,
474       byte[] pubKey,
475       short pubKeyOff,
476       short pubKeyLen,
477       short privKeyPtr,
478       boolean testMode) {
479     if (pubKey[pubKeyOff] == 0x04) { // uncompressed format
480       pubKeyOff += 1;
481       pubKeyLen -= 1;
482     }
483     pubKeyLen = (short) (pubKeyLen / 2);
484     short xPtr = KMByteBlob.instance(pubKey, pubKeyOff, pubKeyLen);
485     short yPtr = KMByteBlob.instance(pubKey, (short) (pubKeyOff + pubKeyLen), pubKeyLen);
486     short coseKey =
487         constructCoseKey(buff, keyType, keyId, keyAlg, curve, xPtr, yPtr, privKeyPtr, testMode);
488     KMCoseKey.cast(coseKey).canonicalize();
489     return coseKey;
490   }
491 
492   /**
493    * Constructs the cose key based on input parameters supplied. All the parameters must be
494    * instantiated from either KMInteger or KMNInteger or KMByteblob types.
495    *
496    * @param keyType instance of KMInteger/KMNInteger which holds valid COSE key types.
497    * @param keyId instance of KMByteBlob which holds key identifier value.
498    * @param keyAlg instance of KMInteger/KMNInteger which holds valid COSE key algorithm.
499    * @param curve instance of KMInteger/KMNInteger which holds valid COSE EC curve.
500    * @param pubX instance of KMByteBlob which holds EC public key's x value.
501    * @param pubY instance of KMByteBlob which holds EC public key's y value.
502    * @param priv instance of KMByteBlob which holds EC private value.
503    * @param includeTestKey flag which identifies whether to construct test key or production key.
504    * @return instance of the KMCoseKey object.
505    */
constructCoseKey( short[] buff, short keyType, short keyId, short keyAlg, short curve, short pubX, short pubY, short priv, boolean includeTestKey)506   public static short constructCoseKey(
507       short[] buff,
508       short keyType,
509       short keyId,
510       short keyAlg,
511       short curve,
512       short pubX,
513       short pubY,
514       short priv,
515       boolean includeTestKey) {
516     short valueIndex = 7;
517     buff[0] = keyType;
518     buff[1] = keyId;
519     buff[2] = keyAlg;
520     buff[3] = curve;
521     buff[4] = pubX;
522     buff[5] = pubY;
523     buff[6] = priv;
524     for (short i = valueIndex; i < 16; i++) {
525       buff[i] = KMType.INVALID_VALUE;
526     }
527     short arrPtr = handleCosePairTags(COSE_KEY_LABELS, buff, valueIndex, includeTestKey);
528     if (includeTestKey) {
529       short testKey =
530           KMCosePairSimpleValueTag.instance(
531               KMNInteger.uint_32(KMCose.COSE_TEST_KEY, (short) 0),
532               KMSimpleValue.instance(KMSimpleValue.NULL));
533       KMArray.cast(arrPtr).add((short) (KMArray.cast(arrPtr).length() - 1), testKey);
534     }
535     arrPtr = KMCoseKey.instance(arrPtr);
536     KMCoseKey.cast(arrPtr).canonicalize();
537     return arrPtr;
538   }
539 
540   /**
541    * Constructs key derivation context which is required to compute HKDF.
542    *
543    * @param publicKeyA public key buffer from the first party.
544    * @param publicKeyAOff start position of the public key buffer from first party.
545    * @param publicKeyALen length of the public key buffer from first party.
546    * @param publicKeyB public key buffer from the second party.
547    * @param publicKeyBOff start position of the public key buffer from second party.
548    * @param publicKeyBLen length of the public key buffer from second party.
549    * @param senderIsA true if caller is first party, false if caller is second party.
550    * @return instance of KMArray.
551    */
constructKdfContext( byte[] publicKeyA, short publicKeyAOff, short publicKeyALen, byte[] publicKeyB, short publicKeyBOff, short publicKeyBLen, boolean senderIsA)552   public static short constructKdfContext(
553       byte[] publicKeyA,
554       short publicKeyAOff,
555       short publicKeyALen,
556       byte[] publicKeyB,
557       short publicKeyBOff,
558       short publicKeyBLen,
559       boolean senderIsA) {
560     short index = 0;
561     // Prepare sender info
562     short senderInfo = KMArray.instance((short) 3);
563     KMArray.cast(senderInfo)
564         .add(index++, KMByteBlob.instance(client, (short) 0, (short) client.length));
565     KMArray.cast(senderInfo).add(index++, KMByteBlob.instance((short) 0));
566     KMArray.cast(senderInfo)
567         .add(
568             index,
569             senderIsA
570                 ? KMByteBlob.instance(publicKeyA, publicKeyAOff, publicKeyALen)
571                 : KMByteBlob.instance(publicKeyB, publicKeyBOff, publicKeyBLen));
572 
573     // Prepare recipient info
574     index = 0;
575     short recipientInfo = KMArray.instance((short) 3);
576     KMArray.cast(recipientInfo)
577         .add(index++, KMByteBlob.instance(server, (short) 0, (short) server.length));
578     KMArray.cast(recipientInfo).add(index++, KMByteBlob.instance((short) 0));
579     KMArray.cast(recipientInfo)
580         .add(
581             index,
582             senderIsA
583                 ? KMByteBlob.instance(publicKeyB, publicKeyBOff, publicKeyBLen)
584                 : KMByteBlob.instance(publicKeyA, publicKeyAOff, publicKeyALen));
585 
586     // supply public info
587     index = 0;
588     short publicInfo = KMArray.instance((short) 2);
589     KMArray.cast(publicInfo).add(index++, KMInteger.uint_16(AES_GCM_KEY_SIZE_BITS));
590     KMArray.cast(publicInfo).add(index, KMByteBlob.instance((short) 0));
591 
592     // construct kdf context
593     index = 0;
594     short arrPtr = KMArray.instance((short) 4);
595     KMArray.cast(arrPtr).add(index++, KMInteger.uint_8(COSE_ALG_AES_GCM_256));
596     KMArray.cast(arrPtr).add(index++, senderInfo);
597     KMArray.cast(arrPtr).add(index++, recipientInfo);
598     KMArray.cast(arrPtr).add(index, publicInfo);
599 
600     return arrPtr;
601   }
602 }
603