olm_account.cpp 15.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * 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_account.h"

/**
* Init memory allocation for account creation.
21
* @return valid memory allocation, NULL otherwise
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
**/
OlmAccount* initializeAccountMemory()
{
    OlmAccount* accountPtr = NULL;
    size_t accountSize = olm_account_size();

    if(NULL != (accountPtr=(OlmAccount*)malloc(accountSize)))
    { // init account object
      accountPtr = olm_account(accountPtr);
      LOGD("## initializeAccountMemory(): success - OLM account size=%lu",accountSize);
    }
    else
    {
      LOGE("## initializeAccountMemory(): failure - OOM");
    }

    return accountPtr;
}

/**
 * Release the account allocation made by initializeAccountMemory().<br>
 * This method MUST be called when java counter part account instance is done.
 *
 */
pedroGitt's avatar
pedroGitt committed
46
JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(releaseAccountJni)(JNIEnv *env, jobject thiz)
47
48
49
50
51
52
53
54
55
56
{
  OlmAccount* accountPtr = NULL;

  LOGD("## releaseAccountJni(): accountPtr=%p",accountPtr);

  if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
  {
      LOGE("## releaseAccountJni(): failure - invalid Account ptr=NULL");
  }
  else
pedroGitt's avatar
pedroGitt committed
57
58
59
  {
    olm_clear_account(accountPtr);

60
    LOGD("## releaseAccountJni(): IN");
pedroGitt's avatar
pedroGitt committed
61
    // even if free(NULL) does not crash, logs are performed for debug purpose
62
63
64
65
66
67
68
69
    free(accountPtr);
    LOGD("## releaseAccountJni(): OUT");
  }
}

/**
* Initialize a new account and return it to JAVA side.<br>
* Since a C prt is returned as a jlong, special care will be taken
70
* to make the cast (OlmAccount* => jlong) platform independent.
71
72
* @return the initialized OlmAccount* instance if init succeed, NULL otherwise
**/
pedroGitt's avatar
pedroGitt committed
73
JNIEXPORT jlong OLM_ACCOUNT_FUNC_DEF(initNewAccountJni)(JNIEnv *env, jobject thiz)
74
{
pedroGitt's avatar
pedroGitt committed
75
76
    OlmAccount *accountPtr = NULL;
    uint8_t *randomBuffPtr = NULL;
77
    size_t accountRetCode;
pedroGitt's avatar
pedroGitt committed
78
    size_t randomSize;
79
80
81
82
83
84
85
86

    // init account memory allocation
    if(NULL == (accountPtr = initializeAccountMemory()))
    {
        LOGE("## initNewAccount(): failure - init account OOM");
    }
    else
    {
87
        // get random buffer size
88
        randomSize = olm_create_account_random_length(accountPtr);
89
90
91
92
        LOGD("## initNewAccount(): randomSize=%lu", randomSize);

        // allocate random buffer
        if((0!=randomSize) && !setRandomInBuffer(&randomBuffPtr, randomSize))
93
        {
pedroGitt's avatar
pedroGitt committed
94
            LOGE("## initNewAccount(): failure - random buffer init");
95
96
        }
        else
pedroGitt's avatar
pedroGitt committed
97
        {
98
            // create account
pedroGitt's avatar
pedroGitt committed
99
            accountRetCode = olm_create_account(accountPtr, (void*)randomBuffPtr, randomSize);
100
101
102
103
104
105
106
107
108
109
            if(accountRetCode == olm_error()) {
                const char *errorMsgPtr = olm_account_last_error(accountPtr);
                LOGE("## initNewAccount(): failure - account creation failed Msg=%s", errorMsgPtr);
             }

            LOGD("## initNewAccount(): success - OLM account created");
            LOGD("## initNewAccount(): success - accountPtr=%p (jlong)(intptr_t)accountPtr=%lld",accountPtr,(jlong)(intptr_t)accountPtr);
        }
    }

pedroGitt's avatar
pedroGitt committed
110
111
112
113
114
    if(NULL != randomBuffPtr)
    {
        free(randomBuffPtr);
    }

115
116
117
    return (jlong)(intptr_t)accountPtr;
}

pedroGitt's avatar
pedroGitt committed
118
119


120
121
122
123
124
125
126
127
// *********************************************************************
// ************************* IDENTITY KEYS API *************************
// *********************************************************************
/**
* Get identity keys: Ed25519 fingerprint key and Curve25519 identity key.<br>
* The keys are returned in the byte array.
* @return a valid byte array if operation succeed, null otherwise
**/
pedroGitt's avatar
pedroGitt committed
128
JNIEXPORT jbyteArray OLM_ACCOUNT_FUNC_DEF(identityKeysJni)(JNIEnv *env, jobject thiz)
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
{
    OlmAccount* accountPtr = NULL;
    size_t identityKeysLength;
    uint8_t *identityKeysBytesPtr;
    size_t keysResult;
    jbyteArray byteArrayRetValue = NULL;

    LOGD("## identityKeys(): accountPtr =%p",accountPtr);

    if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
        LOGE("## identityKeys(): failure - invalid Account ptr=NULL");
    }
    else
    {   // identity keys allocation
        identityKeysLength = olm_account_identity_keys_length(accountPtr);
145
        if(NULL == (identityKeysBytesPtr=(uint8_t*)malloc(identityKeysLength*sizeof(uint8_t))))
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        {
            LOGE("## identityKeys(): failure - identity keys array OOM");
        }
        else
        {   // retrieve key pairs in identityKeysBytesPtr
            keysResult = olm_account_identity_keys(accountPtr, identityKeysBytesPtr, identityKeysLength);
            if(keysResult == olm_error()) {
                const char *errorMsgPtr = olm_account_last_error(accountPtr);
                LOGE("## identityKeys(): failure - error getting identity keys Msg=%s",errorMsgPtr);
            }
            else
            {   // allocate the byte array to be returned to java
                if(NULL == (byteArrayRetValue=env->NewByteArray(identityKeysLength)))
                {
                    LOGE("## identityKeys(): failure - return byte array OOM");
                }
                else
                {
                    env->SetByteArrayRegion(byteArrayRetValue, 0/*offset*/, identityKeysLength, (const jbyte*)identityKeysBytesPtr);
                    LOGD("## identityKeys(): success - result=%ld", keysResult);
                }
            }

            free(identityKeysBytesPtr);
        }
    }

    return byteArrayRetValue;
}

// *********************************************************************
// ************************* ONE TIME KEYS API *************************
// *********************************************************************
/**
 * Get the maximum number of "one time keys" the account can store.
 *
**/
pedroGitt's avatar
pedroGitt committed
183
JNIEXPORT jlong OLM_ACCOUNT_FUNC_DEF(maxOneTimeKeys)(JNIEnv *env, jobject thiz)
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
{
    OlmAccount* accountPtr = NULL;
    size_t maxKeys = -1;

    if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
        LOGE("## maxOneTimeKey(): failure - invalid Account ptr=NULL");
    }
    else
    {
        maxKeys = olm_account_max_number_of_one_time_keys(accountPtr);
    }
    LOGD("## maxOneTimeKey(): Max keys=%ld", maxKeys);

    return (jlong)maxKeys;
}

/**
 * Generate "one time keys".
 * @param aNumberOfKeys number of keys to generate
 * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise
**/
pedroGitt's avatar
pedroGitt committed
206
JNIEXPORT jint OLM_ACCOUNT_FUNC_DEF(generateOneTimeKeys)(JNIEnv *env, jobject thiz, jint aNumberOfKeys)
207
{
pedroGitt's avatar
pedroGitt committed
208
209
    OlmAccount *accountPtr = NULL;
    uint8_t *randomBufferPtr = NULL;
210
    jint retCode = ERROR_CODE_KO;
pedroGitt's avatar
pedroGitt committed
211
    size_t randomLength;
212
213
214
215
216
217
218
219
220
    size_t result;


    if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
        LOGE("## generateOneTimeKeys(): failure - invalid Account ptr");
    }
    else
    {   // keys memory allocation
221
        randomLength = olm_account_generate_one_time_keys_random_length(accountPtr, (size_t)aNumberOfKeys);
pedroGitt's avatar
pedroGitt committed
222
223
        LOGD("## generateOneTimeKeys(): randomLength=%ld", randomLength);

224
        if((0!=randomLength) && !setRandomInBuffer(&randomBufferPtr, randomLength))
225
        {
pedroGitt's avatar
pedroGitt committed
226
            LOGE("## generateOneTimeKeys(): failure - random buffer init");
227
228
        }
        else
pedroGitt's avatar
pedroGitt committed
229
230
231
232
        {
            LOGD("## generateOneTimeKeys(): accountPtr =%p aNumberOfKeys=%d",accountPtr, aNumberOfKeys);

            // retrieve key pairs in keysBytesPtr
233
            result = olm_account_generate_one_time_keys(accountPtr, (size_t)aNumberOfKeys, (void*)randomBufferPtr, randomLength);
234
235
236
237
238
239
240
241
242
243
244
245
            if(result == olm_error()) {
                const char *errorMsgPtr = olm_account_last_error(accountPtr);
                LOGE("## generateOneTimeKeys(): failure - error generating one time keys Msg=%s",errorMsgPtr);
            }
            else
            {
                retCode = ERROR_CODE_OK;
                LOGD("## generateOneTimeKeys(): success - result=%ld", result);
            }
        }
    }

pedroGitt's avatar
pedroGitt committed
246
247
248
249
250
    if(NULL != randomBufferPtr)
    {
        free(randomBufferPtr);
    }

251
252
253
254
    return retCode;
}

/**
255
 * Get "one time keys".<br>
256
257
258
 * Return the public parts of the unpublished "one time keys" for the account
 * @return a valid byte array if operation succeed, null otherwise
**/
pedroGitt's avatar
pedroGitt committed
259
JNIEXPORT jbyteArray OLM_ACCOUNT_FUNC_DEF(oneTimeKeysJni)(JNIEnv *env, jobject thiz)
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
{
    OlmAccount* accountPtr = NULL;
    size_t keysLength;
    uint8_t *keysBytesPtr;
    size_t keysResult;
    jbyteArray byteArrayRetValue = NULL;

    LOGD("## oneTimeKeys(): accountPtr =%p",accountPtr);

    if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
        LOGE("## oneTimeKeys(): failure - invalid Account ptr");
    }
    else
    {   // keys memory allocation
        keysLength = olm_account_one_time_keys_length(accountPtr);
        if(NULL == (keysBytesPtr=(uint8_t *)malloc(keysLength*sizeof(uint8_t))))
        {
            LOGE("## oneTimeKeys(): failure - one time keys array OOM");
        }
        else
        {   // retrieve key pairs in keysBytesPtr
            keysResult = olm_account_one_time_keys(accountPtr, keysBytesPtr, keysLength);
            if(keysResult == olm_error()) {
                const char *errorMsgPtr = olm_account_last_error(accountPtr);
                LOGE("## oneTimeKeys(): failure - error getting one time keys Msg=%s",errorMsgPtr);
            }
            else
            {   // allocate the byte array to be returned to java
                if(NULL == (byteArrayRetValue=env->NewByteArray(keysLength)))
                {
                    LOGE("## oneTimeKeys(): failure - return byte array OOM");
                }
                else
                {
                    env->SetByteArrayRegion(byteArrayRetValue, 0/*offset*/, keysLength, (const jbyte*)keysBytesPtr);
                    LOGD("## oneTimeKeys(): success");
                }
            }

            free(keysBytesPtr);
        }
    }

    return byteArrayRetValue;
}

/**
 * Remove the "one time keys"  that the session used from the account.
 * Return the public parts of the unpublished "one time keys" for the account
 * @param aNativeOlmSessionId session instance
 * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_NO_MATCHING_ONE_TIME_KEYS if no matching keys, ERROR_CODE_KO otherwise
**/
313
JNIEXPORT jint OLM_ACCOUNT_FUNC_DEF(removeOneTimeKeysForSessionJni)(JNIEnv *env, jobject thiz, jlong aNativeOlmSessionId)
314
315
316
317
318
319
320
321
{
    jint retCode = ERROR_CODE_KO;
    OlmAccount* accountPtr = NULL;
    OlmSession* sessionPtr = (OlmSession*)aNativeOlmSessionId;
    size_t result;

    if(NULL == sessionPtr)
    {
322
        LOGE("## removeOneTimeKeysForSessionJni(): failure - invalid session ptr");
323
324
325
    }
    else if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
326
        LOGE("## removeOneTimeKeysForSessionJni(): failure - invalid account ptr");
327
328
329
330
331
332
333
    }
    else
    {
        result = olm_remove_one_time_keys(accountPtr, sessionPtr);
        if(result == olm_error())
        {   // the account doesn't have any matching "one time keys"..
            const char *errorMsgPtr = olm_account_last_error(accountPtr);
334
            LOGW("## removeOneTimeKeysForSessionJni(): failure - removing one time keys Msg=%s",errorMsgPtr);
335
336
337
338
339
340

            retCode = ERROR_CODE_NO_MATCHING_ONE_TIME_KEYS;
        }
        else
        {
            retCode = ERROR_CODE_OK;
341
            LOGD("## removeOneTimeKeysForSessionJni(): success");
342
343
344
345
346
347
348
349
350
351
        }
    }

    return retCode;
}

/**
 * Mark the current set of "one time keys" as being published.
 * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise
**/
352
JNIEXPORT jint OLM_ACCOUNT_FUNC_DEF(markOneTimeKeysAsPublishedJni)(JNIEnv *env, jobject thiz)
353
354
355
356
357
358
359
{
    jint retCode = ERROR_CODE_OK;
    OlmAccount* accountPtr = NULL;
    size_t result;

    if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
360
        LOGE("## markOneTimeKeysAsPublishedJni(): failure - invalid account ptr");
361
362
363
364
365
366
367
368
        retCode = ERROR_CODE_KO;
    }
    else
    {
        result = olm_account_mark_keys_as_published(accountPtr);
        if(result == olm_error())
        {
            const char *errorMsgPtr = olm_account_last_error(accountPtr);
369
            LOGW("## markOneTimeKeysAsPublishedJni(): failure - Msg=%s",errorMsgPtr);
370
371
372
373
            retCode = ERROR_CODE_KO;
        }
        else
        {
374
            LOGD("## markOneTimeKeysAsPublishedJni(): success - retCode=%ld",result);
375
376
377
378
379
380
381
        }
    }

    return retCode;
}

/**
382
383
 * Sign a message with the ed25519 key (fingerprint) for this account.<br>
 * The signed message is returned by the function.
384
 * @param aMessage message to sign
385
 * @return the signed message, null otherwise
386
**/
387
JNIEXPORT jstring OLM_ACCOUNT_FUNC_DEF(signMessageJni)(JNIEnv *env, jobject thiz, jstring aMessage)
388
389
390
{
    OlmAccount* accountPtr = NULL;
    size_t signatureLength;
391
    void* signedMsgPtr;
392
393
394
395
396
    size_t resultSign;
    jstring signedMsgRetValue = NULL;

    if(NULL == aMessage)
    {
397
        LOGE("## signMessageJni(): failure - invalid aMessage param");
398
399
400
    }
    else if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
    {
401
        LOGE("## signMessageJni(): failure - invalid account ptr");
402
403
404
405
406
407
408
    }
    else
    {
        // convert message from JAVA to C string
        const char* messageToSign = env->GetStringUTFChars(aMessage, 0);
        if(NULL == messageToSign)
        {
409
            LOGE("## signMessageJni(): failure - message JNI allocation OOM");
410
411
412
413
414
415
416
        }
        else
        {
            int messageLength = env->GetStringUTFLength(aMessage);

            // signature memory allocation
            signatureLength = olm_account_signature_length(accountPtr);
417
            if(NULL == (signedMsgPtr = (void*)malloc(signatureLength*sizeof(uint8_t))))
418
            {
419
                LOGE("## signMessageJni(): failure - signature allocation OOM");
420
421
422
            }
            else
            {   // sign message
423
424
425
426
427
                resultSign = olm_account_sign(accountPtr,
                                             (void*)messageToSign,
                                             (size_t)messageLength,
                                             signedMsgPtr,
                                             signatureLength);
428
429
430
                if(resultSign == olm_error())
                {
                    const char *errorMsgPtr = olm_account_last_error(accountPtr);
431
                    LOGE("## signMessageJni(): failure - error signing message Msg=%s",errorMsgPtr);
432
433
                }
                else
434
435
436
                {
                    // TODO check if signedMsgPtr needs to be null ended: signedMsgPtr[resultSign]='\0'
                    // convert to jstring
437
                    signedMsgRetValue = env->NewStringUTF((const char*)signedMsgPtr); // UTF8
438
                    LOGD("## signMessageJni(): success - retCode=%ld",resultSign);
439
440
                }

441
                free(signedMsgPtr);
442
443
444
445
446
447
448
449
450
451
452
            }

            // release messageToSign
            env->ReleaseStringUTFChars(aMessage, messageToSign);
        }
    }

    return signedMsgRetValue;
}


pedroGitt's avatar
pedroGitt committed
453
JNIEXPORT jstring OLM_MANAGER_FUNC_DEF(getOlmLibVersion)(JNIEnv* env, jobject thiz)
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
{
  uint8_t majorVer=0, minorVer=0, patchVer=0;
  jstring returnValueStr=0;
  char buff[150];

  olm_get_library_version(&majorVer, &minorVer, &patchVer);
  LOGD("## getOlmLibVersion(): Major=%d Minor=%d Patch=%d", majorVer, minorVer, patchVer);

  snprintf(buff, sizeof(buff), " V%d.%d.%d", majorVer, minorVer, patchVer);
  returnValueStr = env->NewStringUTF((const char*)buff);

  return returnValueStr;
}