olm_outbound_group_session.cpp 18.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * Copyright 2016 OpenMarket Ltd
 *
 * 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
19
using namespace AndroidOlmSdk;
20
21
22
23
24
25
26
27
28
29

/**
 * 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)
{
  OlmOutboundGroupSession* sessionPtr = NULL;

pedroGitt's avatar
pedroGitt committed
30
  LOGD("## releaseSessionJni(): OutBound group session IN");
31
32
33

  if(NULL == (sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
  {
34
      LOGE(" ## releaseSessionJni(): failure - invalid outbound group session instance");
35
36
37
  }
  else
  {
38
39
    LOGD(" ## releaseSessionJni(): sessionPtr=%p",sessionPtr);

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

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

/**
* 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
**/
59
JNIEXPORT jlong OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(createNewSessionJni)(JNIEnv *env, jobject thiz)
60
61
{
    OlmOutboundGroupSession* sessionPtr = NULL;
62
63
    size_t sessionSize = 0;

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

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

    return (jlong)(intptr_t)sessionPtr;
}

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

    LOGD("## initOutboundGroupSessionJni(): IN");
95
96
97

    if(NULL == (sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
    {
98
        LOGE(" ## initOutboundGroupSessionJni(): failure - invalid outbound group session instance");
99
100
101
102
103
    }
    else
    {
        // compute random buffer
        size_t randomLength = olm_init_outbound_group_session_random_length(sessionPtr);
pedroGitt's avatar
pedroGitt committed
104
        LOGW(" ## initOutboundGroupSessionJni(): randomLength=%lu",static_cast<long unsigned int>(randomLength));
105
        if((0!=randomLength) && !setRandomInBuffer(env, &randomBuffPtr, randomLength))
106
        {
107
            LOGE(" ## initOutboundGroupSessionJni(): failure - random buffer init");
108
109
110
111
112
        }
        else
        {
            if(0==randomLength)
            {
113
                LOGW(" ## initOutboundGroupSessionJni(): random buffer is not required");
114
115
            }

116
            size_t sessionResult = olm_init_outbound_group_session(sessionPtr, randomBuffPtr, randomLength);
117
            if(sessionResult == olm_error()) {
118
                LOGE(" ## initOutboundGroupSessionJni(): failure - init outbound session creation  Msg=%s",(const char *)olm_outbound_group_session_last_error(sessionPtr));
119
120
121
122
            }
            else
            {
                retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
123
                LOGD(" ## initOutboundGroupSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
124
125
126
127
            }
        }
      }

128
    if(NULL != randomBuffPtr)
129
    {
130
        free(randomBuffPtr);
131
    }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

    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)
{
    OlmOutboundGroupSession *sessionPtr = NULL;
    uint8_t *sessionIdPtr = NULL;
    jstring returnValueStr=0;

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

    if(NULL == (sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
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
        if(NULL == (sessionIdPtr = (uint8_t*)malloc((lengthSessionId+1)*sizeof(uint8_t))))
158
        {
159
           LOGE(" ## sessionIdentifierJni(): failure - outbound identifier allocation OOM");
160
161
162
        }
        else
        {
163
164
165
            size_t result = olm_outbound_group_session_id(sessionPtr, sessionIdPtr, lengthSessionId);
            if (result == olm_error())
            {
pedroGitt's avatar
pedroGitt committed
166
                LOGE(" ## sessionIdentifierJni(): failure - outbound group session identifier failure Msg=%s",reinterpret_cast<const char*>(olm_outbound_group_session_last_error(sessionPtr)));
167
168
169
170
171
            }
            else
            {
                // update length
                sessionIdPtr[result] = static_cast<char>('\0');
pedroGitt's avatar
pedroGitt committed
172
                LOGD(" ## sessionIdentifierJni(): success - outbound group session identifier result=%lu sessionId=%s",static_cast<long unsigned int>(result), reinterpret_cast<char*>(sessionIdPtr));
173
174
                returnValueStr = env->NewStringUTF((const char*)sessionIdPtr);
            }
175

176
177
178
179
            // free alloc
            free(sessionIdPtr);
        }
    }
180

181
    return returnValueStr;
182
183
184
}


185
186
187
188
189
190
191
/**
* 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)
192
{
193
194
    OlmOutboundGroupSession *sessionPtr = NULL;
    jint indexRetValue = 0;
195

196
    LOGD("## messageIndexJni(): IN");
197

198
199
    if(NULL == (sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
    {
200
        LOGE(" ## messageIndexJni(): failure - invalid outbound group session instance");
201
202
    }
    else
203
    {
204
        indexRetValue = static_cast<jint>(olm_outbound_group_session_message_index(sessionPtr));
205
    }
206
    LOGD(" ## messageIndexJni(): success - index=%d",indexRetValue);
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

    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)
{
    OlmOutboundGroupSession *sessionPtr = NULL;
    uint8_t *sessionKeyPtr = NULL;
    jstring returnValueStr=0;

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

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

233
        if(NULL == (sessionKeyPtr = (uint8_t*)malloc((sessionKeyLength+1)*sizeof(uint8_t))))
234
        {
235
           LOGE(" ## sessionKeyJni(): failure - session key allocation OOM");
236
237
238
        }
        else
        {
239
240
241
            size_t result = olm_outbound_group_session_key(sessionPtr, sessionKeyPtr, sessionKeyLength);
            if (result == olm_error())
            {
242
                LOGE(" ## sessionKeyJni(): failure - session key failure Msg=%s",(const char *)olm_outbound_group_session_last_error(sessionPtr));
243
244
245
246
247
            }
            else
            {
                // update length
                sessionKeyPtr[result] = static_cast<char>('\0');
pedroGitt's avatar
pedroGitt committed
248
                LOGD(" ## sessionKeyJni(): success - outbound group session key result=%lu sessionKey=%s",static_cast<long unsigned int>(result), reinterpret_cast<char*>(sessionKeyPtr));
249
250
                returnValueStr = env->NewStringUTF((const char*)sessionKeyPtr);
            }
251

252
253
            // free alloc
            free(sessionKeyPtr);
254
255
256
257
258
259
        }
    }

    return returnValueStr;
}

260
261

JNIEXPORT jstring OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jstring aClearMsg)
262
{
263
264
265
266
    jstring encryptedMsgRetValue = 0;
    OlmOutboundGroupSession *sessionPtr = NULL;
    const char *clearMsgPtr = NULL;
    uint8_t *encryptedMsgPtr = NULL;
267

268
    LOGD("## encryptMessageJni(): IN");
269

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

288
289
        // compute max encrypted length
        size_t encryptedMsgLength = olm_group_encrypt_message_length(sessionPtr,clearMsgLength);
290
        if(NULL == (encryptedMsgPtr = (uint8_t*)malloc((encryptedMsgLength+1)*sizeof(uint8_t))))
291
        {
292
            LOGE(" ## encryptMessageJni(): failure - encryptedMsgPtr buffer OOM");
293
294
295
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
296
            LOGD(" ## encryptMessageJni(): estimated encryptedMsgLength=%lu",static_cast<long unsigned int>(encryptedMsgLength));
297

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

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

    // free alloc
319
    if(NULL != clearMsgPtr)
320
    {
321
        env->ReleaseStringUTFChars(aClearMsg, clearMsgPtr);
322
323
    }

324
    if(NULL != encryptedMsgPtr)
325
    {
326
        free(encryptedMsgPtr);
327
328
    }

329
    return encryptedMsgRetValue;
330
331
332
}


333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/**
* 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;
    void *pickledPtr = NULL;
    OlmOutboundGroupSession* sessionPtr = NULL;

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

    if(NULL == (sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid session ptr");
    }
    else if(0 == aKey)
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid key");
    }
    else if(0 == aErrorMsg)
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid error object");
    }
    else if(0 == (errorMsgJClass = env->GetObjectClass(aErrorMsg)))
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error class");
    }
    else if(0 == (errorMsgMethodId = env->GetMethodID(errorMsgJClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")))
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error method ID");
    }
    else if(NULL == (keyPtr = env->GetStringUTFChars(aKey, 0)))
    {
        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
379
        LOGD(" ## serializeDataWithKeyJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
        LOGD(" ## serializeDataWithKeyJni(): key=%s",(char const *)keyPtr);

        if(NULL == (pickledPtr = (void*)malloc((pickledLength+1)*sizeof(uint8_t))))
        {
            LOGE(" ## serializeDataWithKeyJni(): failure - pickledPtr buffer OOM");
        }
        else
        {
            size_t result = olm_pickle_outbound_group_session(sessionPtr,
                                                             (void const *)keyPtr,
                                                              keyLength,
                                                              (void*)pickledPtr,
                                                              pickledLength);
            if(result == olm_error())
            {
                const char *errorMsgPtr = olm_outbound_group_session_last_error(sessionPtr);
                LOGE(" ## serializeDataWithKeyJni(): failure - olm_pickle_outbound_group_session() Msg=%s",errorMsgPtr);

                if(0 != (errorJstring = env->NewStringUTF(errorMsgPtr)))
                {
                    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
408
                LOGD(" ## serializeDataWithKeyJni(): success - result=%lu pickled=%s", static_cast<long unsigned int>(result), static_cast<char*>(pickledPtr));
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
            }
        }
    }

    // free alloc
    if(NULL != keyPtr)
    {
     env->ReleaseStringUTFChars(aKey, keyPtr);
    }

    if(NULL != pickledPtr)
    {
        free(pickledPtr);
    }

    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");

    if(NULL == (sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
    {
        LOGE(" ## initWithSerializedDataJni(): failure - session failure OOM");
    }
    else if(0 == aKey)
    {
        LOGE(" ## initWithSerializedDataJni(): failure - invalid key");
    }
    else if(0 == aSerializedData)
    {
        LOGE(" ## initWithSerializedDataJni(): failure - serialized data");
    }
    else if(NULL == (keyPtr = env->GetStringUTFChars(aKey, 0)))
    {
        LOGE(" ## initWithSerializedDataJni(): failure - keyPtr JNI allocation OOM");
    }
    else if(NULL == (pickledPtr = env->GetStringUTFChars(aSerializedData, 0)))
    {
        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
470
471
472
473
474
475
476
477
        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);
        if(result == olm_error())
        {
            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
483
484
485
486
487
488
489
490
491
492
493
494
        }
    }

    // free alloc
    if(NULL != keyPtr)
    {
        env->ReleaseStringUTFChars(aKey, keyPtr);
    }

    if(NULL != pickledPtr)
    {
        env->ReleaseStringUTFChars(aSerializedData, pickledPtr);
    }

    return errorMessageRetValue;
}
495