olm_outbound_group_session.cpp 18.1 KB
Newer Older
1
2
/*
 * Copyright 2016 OpenMarket Ltd
ylecollen's avatar
ylecollen committed
3
 * Copyright 2016 Vector Creations Ltd
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "olm_outbound_group_session.h"

pedroGitt's avatar
pedroGitt committed
20
using namespace AndroidOlmSdk;
21
22
23
24
25
26
27
28

/**
 * Release the session allocation made by initializeOutboundGroupSessionMemory().<br>
 * This method MUST be called when java counter part account instance is done.
 *
 */
JNIEXPORT void OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(releaseSessionJni)(JNIEnv *env, jobject thiz)
{
29
    LOGD("## releaseSessionJni(): OutBound group session IN");
30

31
    OlmOutboundGroupSession* sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz);
32

33
34
35
36
37
38
39
    if (!sessionPtr)
    {
        LOGE(" ## releaseSessionJni(): failure - invalid outbound group session instance");
    }
    else
    {
        LOGD(" ## releaseSessionJni(): sessionPtr=%p",sessionPtr);
40

41
#ifdef ENABLE_JNI_LOG
42
43
        size_t retCode = olm_clear_outbound_group_session(sessionPtr);
        LOGD(" ## releaseSessionJni(): clear_outbound_group_session=%lu",static_cast<long unsigned int>(retCode));
44
#else
45
        olm_clear_outbound_group_session(sessionPtr);
46
#endif
47

48
49
50
51
        LOGD(" ## releaseSessionJni(): free IN");
        free(sessionPtr);
        LOGD(" ## releaseSessionJni(): free OUT");
    }
52
53
54
55
56
57
58
59
}

/**
* Initialize a new outbound group session and return it to JAVA side.<br>
* Since a C prt is returned as a jlong, special care will be taken
* to make the cast (OlmOutboundGroupSession* => jlong) platform independent.
* @return the initialized OlmOutboundGroupSession* instance if init succeed, NULL otherwise
**/
60
JNIEXPORT jlong OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(createNewSessionJni)(JNIEnv *env, jobject thiz)
61
62
{
    OlmOutboundGroupSession* sessionPtr = NULL;
63
64
    size_t sessionSize = 0;

65
    LOGD("## createNewSessionJni(): outbound group session IN");
66
    sessionSize = olm_outbound_group_session_size();
67

68
    if (0 == sessionSize)
69
    {
70
        LOGE(" ## createNewSessionJni(): failure - outbound group session size = 0");
71
    }
72
    else if (!(sessionPtr = (OlmOutboundGroupSession*)malloc(sessionSize)))
73
    {
74
75
        sessionPtr = olm_outbound_group_session(sessionPtr);
        LOGD(" ## createNewSessionJni(): success - outbound group session size=%lu",static_cast<long unsigned int>(sessionSize));
76
77
78
    }
    else
    {
79
        LOGE(" ## createNewSessionJni(): failure - outbound group session OOM");
80
81
82
83
84
85
    }

    return (jlong)(intptr_t)sessionPtr;
}

/**
86
 * Start a new outbound session.<br>
87
88
 * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise
 */
89
JNIEXPORT jint OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(initOutboundGroupSessionJni)(JNIEnv *env, jobject thiz)
90
91
{
    jint retCode = ERROR_CODE_KO;
92
93

    LOGD("## initOutboundGroupSessionJni(): IN");
94

95
96
97
    OlmOutboundGroupSession *sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz);

    if (!sessionPtr)
98
    {
99
        LOGE(" ## initOutboundGroupSessionJni(): failure - invalid outbound group session instance");
100
101
102
103
104
    }
    else
    {
        // compute random buffer
        size_t randomLength = olm_init_outbound_group_session_random_length(sessionPtr);
105
106
        uint8_t *randomBuffPtr = NULL;

pedroGitt's avatar
pedroGitt committed
107
        LOGW(" ## initOutboundGroupSessionJni(): randomLength=%lu",static_cast<long unsigned int>(randomLength));
108
109

        if ((0 != randomLength) && !setRandomInBuffer(env, &randomBuffPtr, randomLength))
110
        {
111
            LOGE(" ## initOutboundGroupSessionJni(): failure - random buffer init");
112
113
114
        }
        else
        {
115
            if (0 == randomLength)
116
            {
117
                LOGW(" ## initOutboundGroupSessionJni(): random buffer is not required");
118
119
            }

120
            size_t sessionResult = olm_init_outbound_group_session(sessionPtr, randomBuffPtr, randomLength);
121
122

            if (sessionResult == olm_error()) {
123
                LOGE(" ## initOutboundGroupSessionJni(): failure - init outbound session creation  Msg=%s",(const char *)olm_outbound_group_session_last_error(sessionPtr));
124
125
126
127
            }
            else
            {
                retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
128
                LOGD(" ## initOutboundGroupSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
129
130
            }

131
132
            free(randomBuffPtr);
        }
133
    }
134
135
136
137
138
139
140
141
142
143

    return retCode;
}

/**
* Get a base64-encoded identifier for this outbound group session.
*/
JNIEXPORT jstring OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(sessionIdentifierJni)(JNIEnv *env, jobject thiz)
{
    LOGD("## sessionIdentifierJni(): outbound group session IN");
144
145
    OlmOutboundGroupSession *sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz);
    jstring returnValueStr=0;
146

147
    if (!sessionPtr)
148
    {
149
        LOGE(" ## sessionIdentifierJni(): failure - invalid outbound group session instance");
150
151
152
    }
    else
    {
153
154
        // get the size to alloc
        size_t lengthSessionId = olm_outbound_group_session_id_length(sessionPtr);
pedroGitt's avatar
pedroGitt committed
155
        LOGD(" ## sessionIdentifierJni(): outbound group session lengthSessionId=%lu",static_cast<long unsigned int>(lengthSessionId));
156

157
158
159
        uint8_t *sessionIdPtr =  (uint8_t*)malloc((lengthSessionId+1)*sizeof(uint8_t));

        if (!sessionIdPtr)
160
        {
161
           LOGE(" ## sessionIdentifierJni(): failure - outbound identifier allocation OOM");
162
163
164
        }
        else
        {
165
            size_t result = olm_outbound_group_session_id(sessionPtr, sessionIdPtr, lengthSessionId);
166

167
168
            if (result == olm_error())
            {
pedroGitt's avatar
pedroGitt committed
169
                LOGE(" ## sessionIdentifierJni(): failure - outbound group session identifier failure Msg=%s",reinterpret_cast<const char*>(olm_outbound_group_session_last_error(sessionPtr)));
170
171
172
173
174
            }
            else
            {
                // update length
                sessionIdPtr[result] = static_cast<char>('\0');
pedroGitt's avatar
pedroGitt committed
175
                LOGD(" ## sessionIdentifierJni(): success - outbound group session identifier result=%lu sessionId=%s",static_cast<long unsigned int>(result), reinterpret_cast<char*>(sessionIdPtr));
176
177
                returnValueStr = env->NewStringUTF((const char*)sessionIdPtr);
            }
178

179
180
181
182
            // free alloc
            free(sessionIdPtr);
        }
    }
183

184
    return returnValueStr;
185
186
187
}


188
189
190
191
192
193
194
/**
* Get the current message index for this session.<br>
* Each message is sent with an increasing index, this
* method returns the index for the next message.
* @return current session index
*/
JNIEXPORT jint OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(messageIndexJni)(JNIEnv *env, jobject thiz)
195
{
196
197
    OlmOutboundGroupSession *sessionPtr = NULL;
    jint indexRetValue = 0;
198

199
    LOGD("## messageIndexJni(): IN");
200

201
    if (!(sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
202
    {
203
        LOGE(" ## messageIndexJni(): failure - invalid outbound group session instance");
204
205
    }
    else
206
    {
207
        indexRetValue = static_cast<jint>(olm_outbound_group_session_message_index(sessionPtr));
208
    }
209

210
    LOGD(" ## messageIndexJni(): success - index=%d",indexRetValue);
211
212
213
214
215
216
217
218
219
220

    return indexRetValue;
}

/**
* Get the base64-encoded current ratchet key for this session.<br>
*/
JNIEXPORT jstring OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(sessionKeyJni)(JNIEnv *env, jobject thiz)
{
    LOGD("## sessionKeyJni(): outbound group session IN");
221
222
    OlmOutboundGroupSession *sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz);
    jstring returnValueStr = 0;
223

224
    if (!sessionPtr)
225
    {
226
        LOGE(" ## sessionKeyJni(): failure - invalid outbound group session instance");
227
228
229
    }
    else
    {
230
231
        // get the size to alloc
        size_t sessionKeyLength = olm_outbound_group_session_key_length(sessionPtr);
pedroGitt's avatar
pedroGitt committed
232
        LOGD(" ## sessionKeyJni(): sessionKeyLength=%lu",static_cast<long unsigned int>(sessionKeyLength));
233

234
235
236
        uint8_t *sessionKeyPtr = (uint8_t*)malloc((sessionKeyLength+1)*sizeof(uint8_t));

        if (!sessionKeyPtr)
237
        {
238
           LOGE(" ## sessionKeyJni(): failure - session key allocation OOM");
239
240
241
        }
        else
        {
242
            size_t result = olm_outbound_group_session_key(sessionPtr, sessionKeyPtr, sessionKeyLength);
243

244
245
            if (result == olm_error())
            {
246
                LOGE(" ## sessionKeyJni(): failure - session key failure Msg=%s",(const char *)olm_outbound_group_session_last_error(sessionPtr));
247
248
249
250
251
            }
            else
            {
                // update length
                sessionKeyPtr[result] = static_cast<char>('\0');
pedroGitt's avatar
pedroGitt committed
252
                LOGD(" ## sessionKeyJni(): success - outbound group session key result=%lu sessionKey=%s",static_cast<long unsigned int>(result), reinterpret_cast<char*>(sessionKeyPtr));
253
254
                returnValueStr = env->NewStringUTF((const char*)sessionKeyPtr);
            }
255

256
257
            // free alloc
            free(sessionKeyPtr);
258
259
260
261
262
263
        }
    }

    return returnValueStr;
}

264

265
JNIEXPORT jstring OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jbyteArray aClearMsgBuffer)
266
{
267
268
    LOGD("## encryptMessageJni(): IN");

269
270
    jstring encryptedMsgRetValue = 0;
    OlmOutboundGroupSession *sessionPtr = NULL;
271
    jbyte* clearMsgPtr = NULL;
272

273
    if (!(sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
274
    {
275
        LOGE(" ## encryptMessageJni(): failure - invalid outbound group session ptr=NULL");
276
    }
277
    else if (!aClearMsgBuffer)
278
    {
279
        LOGE(" ## encryptMessageJni(): failure - invalid clear message");
280
    }
281
    else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, NULL)))
282
    {
283
        LOGE(" ## encryptMessageJni(): failure - clear message JNI allocation OOM");
284
285
286
    }
    else
    {
287
        // get clear message length
288
        size_t clearMsgLength = (size_t)env->GetArrayLength(aClearMsgBuffer);
pedroGitt's avatar
pedroGitt committed
289
        LOGD(" ## encryptMessageJni(): clearMsgLength=%lu",static_cast<long unsigned int>(clearMsgLength));
290

291
292
        // compute max encrypted length
        size_t encryptedMsgLength = olm_group_encrypt_message_length(sessionPtr,clearMsgLength);
293
294
295
        uint8_t *encryptedMsgPtr = (uint8_t*)malloc((encryptedMsgLength+1)*sizeof(uint8_t));

        if (!encryptedMsgPtr)
296
        {
297
            LOGE(" ## encryptMessageJni(): failure - encryptedMsgPtr buffer OOM");
298
299
300
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
301
            LOGD(" ## encryptMessageJni(): estimated encryptedMsgLength=%lu",static_cast<long unsigned int>(encryptedMsgLength));
302

303
            size_t encryptedLength = olm_group_encrypt(sessionPtr,
304
305
306
307
                                                       (uint8_t*)clearMsgPtr,
                                                       clearMsgLength,
                                                       encryptedMsgPtr,
                                                       encryptedMsgLength);
308
            if (encryptedLength == olm_error())
309
            {
310
                LOGE(" ## encryptMessageJni(): failure - olm_group_encrypt Msg=%s",(const char *)olm_outbound_group_session_last_error(sessionPtr));
311
312
313
            }
            else
            {
314
                // update decrypted buffer size
315
                encryptedMsgPtr[encryptedLength] = static_cast<char>('\0');
316

pedroGitt's avatar
pedroGitt committed
317
                LOGD(" ## encryptMessageJni(): encrypted returnedLg=%lu plainTextMsgPtr=%s",static_cast<long unsigned int>(encryptedLength), reinterpret_cast<char*>(encryptedMsgPtr));
318
                encryptedMsgRetValue = env->NewStringUTF((const char*)encryptedMsgPtr);
319
            }
320
321
322

            free(encryptedMsgPtr);
         }
323
      }
324
325

    // free alloc
326
    if (clearMsgPtr)
327
    {
328
        env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT);
329
330
    }

331
    return encryptedMsgRetValue;
332
333
334
}


335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/**
* Serialize and encrypt session instance into a base64 string.<br>
* @param aKey key used to encrypt the serialized session data
* @param[out] aErrorMsg error message set if operation failed
* @return a base64 string if operation succeed, null otherwise
**/
JNIEXPORT jstring OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(serializeDataWithKeyJni)(JNIEnv *env, jobject thiz, jstring aKey, jobject aErrorMsg)
{
    jstring pickledDataRetValue = 0;
    jclass errorMsgJClass = 0;
    jmethodID errorMsgMethodId = 0;
    jstring errorJstring = 0;
    const char *keyPtr = NULL;
    OlmOutboundGroupSession* sessionPtr = NULL;

    LOGD("## outbound group session serializeDataWithKeyJni(): IN");

352
    if (!(sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
353
354
355
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid session ptr");
    }
356
    else if (!aKey)
357
358
359
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid key");
    }
360
    else if (!aErrorMsg)
361
362
363
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid error object");
    }
364
    else if (!(errorMsgJClass = env->GetObjectClass(aErrorMsg)))
365
366
367
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error class");
    }
368
    else if (!(errorMsgMethodId = env->GetMethodID(errorMsgJClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")))
369
370
371
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error method ID");
    }
372
    else if (!(keyPtr = env->GetStringUTFChars(aKey, 0)))
373
374
375
376
377
378
379
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - keyPtr JNI allocation OOM");
    }
    else
    {
        size_t pickledLength = olm_pickle_outbound_group_session_length(sessionPtr);
        size_t keyLength = (size_t)env->GetStringUTFLength(aKey);
pedroGitt's avatar
pedroGitt committed
380
        LOGD(" ## serializeDataWithKeyJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
381
382
        LOGD(" ## serializeDataWithKeyJni(): key=%s",(char const *)keyPtr);

383
384
385
        void *pickledPtr = malloc((pickledLength+1)*sizeof(uint8_t));

        if(!pickledPtr)
386
387
388
389
390
391
392
393
394
395
        {
            LOGE(" ## serializeDataWithKeyJni(): failure - pickledPtr buffer OOM");
        }
        else
        {
            size_t result = olm_pickle_outbound_group_session(sessionPtr,
                                                             (void const *)keyPtr,
                                                              keyLength,
                                                              (void*)pickledPtr,
                                                              pickledLength);
396
            if (result == olm_error())
397
398
399
400
            {
                const char *errorMsgPtr = olm_outbound_group_session_last_error(sessionPtr);
                LOGE(" ## serializeDataWithKeyJni(): failure - olm_pickle_outbound_group_session() Msg=%s",errorMsgPtr);

401
                if (!(errorJstring = env->NewStringUTF(errorMsgPtr)))
402
403
404
405
406
407
408
409
410
                {
                    env->CallObjectMethod(aErrorMsg, errorMsgMethodId, errorJstring);
                }
            }
            else
            {
                // build success output
                (static_cast<char*>(pickledPtr))[pickledLength] = static_cast<char>('\0');
                pickledDataRetValue = env->NewStringUTF((const char*)pickledPtr);
pedroGitt's avatar
pedroGitt committed
411
                LOGD(" ## serializeDataWithKeyJni(): success - result=%lu pickled=%s", static_cast<long unsigned int>(result), static_cast<char*>(pickledPtr));
412
413
414
            }
        }

415
        free(pickledPtr);
416
417
    }

418
419
    // free alloc
    if (keyPtr)
420
    {
421
        env->ReleaseStringUTFChars(aKey, keyPtr);
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
    }

    return pickledDataRetValue;
}


JNIEXPORT jstring OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(initWithSerializedDataJni)(JNIEnv *env, jobject thiz, jstring aSerializedData, jstring aKey)
{
    OlmOutboundGroupSession* sessionPtr = NULL;
    jstring errorMessageRetValue = 0;
    const char *keyPtr = NULL;
    const char *pickledPtr = NULL;

    LOGD("## initWithSerializedDataJni(): IN");

437
    if (!(sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
438
439
440
    {
        LOGE(" ## initWithSerializedDataJni(): failure - session failure OOM");
    }
441
    else if (!aKey)
442
443
444
    {
        LOGE(" ## initWithSerializedDataJni(): failure - invalid key");
    }
445
    else if (!aSerializedData)
446
447
448
    {
        LOGE(" ## initWithSerializedDataJni(): failure - serialized data");
    }
449
    else if (!(keyPtr = env->GetStringUTFChars(aKey, 0)))
450
451
452
    {
        LOGE(" ## initWithSerializedDataJni(): failure - keyPtr JNI allocation OOM");
    }
453
    else if (!(pickledPtr = env->GetStringUTFChars(aSerializedData, 0)))
454
455
456
457
458
459
460
    {
        LOGE(" ## initWithSerializedDataJni(): failure - pickledPtr JNI allocation OOM");
    }
    else
    {
        size_t pickledLength = (size_t)env->GetStringUTFLength(aSerializedData);
        size_t keyLength = (size_t)env->GetStringUTFLength(aKey);
pedroGitt's avatar
pedroGitt committed
461
        LOGD(" ## initWithSerializedDataJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
462
463
464
465
466
467
468
469
        LOGD(" ## initWithSerializedDataJni(): key=%s",(char const *)keyPtr);
        LOGD(" ## initWithSerializedDataJni(): pickled=%s",(char const *)pickledPtr);

        size_t result = olm_unpickle_outbound_group_session(sessionPtr,
                                                            (void const *)keyPtr,
                                                            keyLength,
                                                            (void*)pickledPtr,
                                                            pickledLength);
470
        if (result == olm_error())
471
472
473
474
475
476
477
        {
            const char *errorMsgPtr = olm_outbound_group_session_last_error(sessionPtr);
            LOGE(" ## initWithSerializedDataJni(): failure - olm_unpickle_outbound_group_session() Msg=%s",errorMsgPtr);
            errorMessageRetValue = env->NewStringUTF(errorMsgPtr);
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
478
            LOGD(" ## initWithSerializedDataJni(): success - result=%lu ", static_cast<long unsigned int>(result));
479
480
481
482
        }
    }

    // free alloc
483
    if (keyPtr)
484
485
486
487
    {
        env->ReleaseStringUTFChars(aKey, keyPtr);
    }

488
    if (pickledPtr)
489
490
491
492
493
494
    {
        env->ReleaseStringUTFChars(aSerializedData, pickledPtr);
    }

    return errorMessageRetValue;
}
495