1 /*
2  * Copyright 2020, 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 #include <inttypes.h>
18 
19 #include "EicCommon.h"
20 #include "EicSession.h"
21 
22 // Global used for assigning ids for session objects.
23 //
24 static uint32_t gSessionLastIdAssigned = 0;
25 
26 // The current session object or NULL if never initialized or if it has been shut down.
27 //
28 static EicSession* gSessionCurrent = NULL;
29 
eicSessionGetForId(uint32_t sessionId)30 EicSession* eicSessionGetForId(uint32_t sessionId) {
31     if (gSessionCurrent != NULL && gSessionCurrent->id == sessionId) {
32         return gSessionCurrent;
33     }
34     return NULL;
35 }
36 
eicSessionInit(EicSession * ctx)37 bool eicSessionInit(EicSession* ctx) {
38     eicMemSet(ctx, '\0', sizeof(EicSession));
39 
40     if (!eicNextId(&gSessionLastIdAssigned)) {
41         eicDebug("Error getting id for object");
42         return false;
43     }
44     ctx->id = gSessionLastIdAssigned;
45 
46     do {
47         if (!eicOpsRandom((uint8_t*)&(ctx->authChallenge), sizeof(ctx->authChallenge))) {
48             eicDebug("Failed generating random challenge");
49             return false;
50         }
51     } while (ctx->authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET);
52 
53     if (!eicOpsCreateEcKey(ctx->ephemeralPrivateKey, ctx->ephemeralPublicKey)) {
54         eicDebug("Error creating ephemeral key-pair");
55         return false;
56     }
57 
58     gSessionCurrent = ctx;
59     eicDebug("Initialized session with id %" PRIu32, ctx->id);
60     return true;
61 }
62 
eicSessionShutdown(EicSession * ctx)63 bool eicSessionShutdown(EicSession* ctx) {
64     if (ctx->id == 0) {
65         eicDebug("Trying to shut down session with id 0");
66         return false;
67     }
68     eicDebug("Shut down session with id %" PRIu32, ctx->id);
69     eicMemSet(ctx, '\0', sizeof(EicSession));
70     gSessionCurrent = NULL;
71     return true;
72 }
73 
eicSessionGetId(EicSession * ctx,uint32_t * outId)74 bool eicSessionGetId(EicSession* ctx, uint32_t* outId) {
75     *outId = ctx->id;
76     return true;
77 }
78 
eicSessionGetAuthChallenge(EicSession * ctx,uint64_t * outAuthChallenge)79 bool eicSessionGetAuthChallenge(EicSession* ctx, uint64_t* outAuthChallenge) {
80     *outAuthChallenge = ctx->authChallenge;
81     return true;
82 }
83 
eicSessionGetEphemeralKeyPair(EicSession * ctx,uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE])84 bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
85                                    uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
86     eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
87     ctx->getEphemeralKeyPairCalled = true;
88     return true;
89 }
90 
eicSessionSetReaderEphemeralPublicKey(EicSession * ctx,const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE])91 bool eicSessionSetReaderEphemeralPublicKey(
92         EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]) {
93     eicMemCpy(ctx->readerEphemeralPublicKey, readerEphemeralPublicKey, EIC_P256_PUB_KEY_SIZE);
94     ctx->readerEphemeralPublicKeySize = EIC_P256_PUB_KEY_SIZE;
95     return true;
96 }
97 
eicSessionSetSessionTranscript(EicSession * ctx,const uint8_t * sessionTranscript,size_t sessionTranscriptSize)98 bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
99                                     size_t sessionTranscriptSize) {
100     // If mdoc session encryption is in use, only accept the
101     // SessionTranscript if X and Y from the ephemeral key we created
102     // is somewhere in SessionTranscript...
103     //
104     if (ctx->getEphemeralKeyPairCalled) {
105         if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
106                       EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
107             eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
108             return false;
109         }
110         if (eicMemMem(sessionTranscript, sessionTranscriptSize,
111                       ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
112                       EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
113             eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
114             return false;
115         }
116     }
117 
118     // To save space we only store the SHA-256 of SessionTranscript
119     //
120     EicSha256Ctx shaCtx;
121     eicOpsSha256Init(&shaCtx);
122     eicOpsSha256Update(&shaCtx, sessionTranscript, sessionTranscriptSize);
123     eicOpsSha256Final(&shaCtx, ctx->sessionTranscriptSha256);
124     return true;
125 }
126