Skip to content

Commit 78796fd

Browse files
committed
set error state if cipher_migrate fails
1 parent 99d36b4 commit 78796fd

File tree

6 files changed

+186
-49
lines changed

6 files changed

+186
-49
lines changed

src/crypto.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,39 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
111111
} else
112112
#endif
113113
#ifdef SQLCIPHER_TEST
114-
if( sqlite3StrICmp(zLeft,"cipher_test")==0 ){
114+
if( sqlite3StrICmp(zLeft,"cipher_test_on")==0 ){
115115
if( zRight ) {
116-
if(sqlite3StrICmp(zRight, "fail_next_encrypt")) {
117-
sqlcipher_set_test_flags(sqlcipher_get_test_flags() ^ TEST_FAIL_NEXT_ENCRYPT);
116+
unsigned int flags = sqlcipher_get_test_flags();
117+
if(sqlite3StrICmp(zRight, "fail_encrypt")==0) {
118+
flags |= TEST_FAIL_ENCRYPT;
118119
} else
119-
if(sqlite3StrICmp(zRight, "fail_next_decrypt")) {
120-
sqlcipher_set_test_flags(sqlcipher_get_test_flags() ^ TEST_FAIL_NEXT_DECRYPT);
121-
}
122-
} else {
123-
char *flags = sqlite3_mprintf("%d", sqlcipher_get_test_flags());
124-
codec_vdbe_return_string(pParse, "cipher_test", flags, P4_DYNAMIC);
120+
if(sqlite3StrICmp(zRight, "fail_decrypt")==0) {
121+
flags |= TEST_FAIL_DECRYPT;
122+
} else
123+
if(sqlite3StrICmp(zRight, "fail_migrate")==0) {
124+
flags |= TEST_FAIL_MIGRATE;
125+
}
126+
sqlcipher_set_test_flags(flags);
127+
}
128+
} else
129+
if( sqlite3StrICmp(zLeft,"cipher_test_off")==0 ){
130+
if( zRight ) {
131+
unsigned int flags = sqlcipher_get_test_flags();
132+
if(sqlite3StrICmp(zRight, "fail_encrypt")==0) {
133+
flags &= ~TEST_FAIL_ENCRYPT;
134+
} else
135+
if(sqlite3StrICmp(zRight, "fail_decrypt")==0) {
136+
flags &= ~TEST_FAIL_DECRYPT;
137+
} else
138+
if(sqlite3StrICmp(zRight, "fail_migrate")==0) {
139+
flags &= ~TEST_FAIL_MIGRATE;
140+
}
141+
sqlcipher_set_test_flags(flags);
125142
}
143+
} else
144+
if( sqlite3StrICmp(zLeft,"cipher_test")==0 ){
145+
char *flags = sqlite3_mprintf("%i", sqlcipher_get_test_flags());
146+
codec_vdbe_return_string(pParse, "cipher_test", flags, P4_DYNAMIC);
126147
}else
127148
#endif
128149
if( sqlite3StrICmp(zLeft, "cipher_fips_status")== 0 && !zRight ){
@@ -157,8 +178,12 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
157178
} else
158179
if( sqlite3StrICmp(zLeft, "cipher_migrate")==0 && !zRight ){
159180
if(ctx){
160-
char *migrate_status = sqlite3_mprintf("%d", sqlcipher_codec_ctx_migrate(ctx));
181+
int status = sqlcipher_codec_ctx_migrate(ctx);
182+
char *migrate_status = sqlite3_mprintf("%d", status);
161183
codec_vdbe_return_string(pParse, "cipher_migrate", migrate_status, P4_DYNAMIC);
184+
if(status != SQLITE_OK) {
185+
sqlcipher_codec_ctx_set_error(ctx, status);
186+
}
162187
}
163188
} else
164189
if( sqlite3StrICmp(zLeft, "cipher_provider")==0 && !zRight ){
@@ -709,7 +734,7 @@ static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
709734

710735
rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_DECRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
711736
#ifdef SQLCIPHER_TEST
712-
if((sqlcipher_get_test_flags() & TEST_FAIL_NEXT_ENCRYPT) > 0) rc = SQLITE_ERROR;
737+
if((sqlcipher_get_test_flags() & TEST_FAIL_ENCRYPT) > 0) rc = SQLITE_ERROR;
713738
#endif
714739
if(rc != SQLITE_OK) { /* clear results of failed cipher operation and set error */
715740
sqlcipher_memset((unsigned char*) buffer+offset, 0, page_sz-offset);
@@ -734,7 +759,7 @@ static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
734759
}
735760
rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
736761
#ifdef SQLCIPHER_TEST
737-
if((sqlcipher_get_test_flags() & TEST_FAIL_NEXT_DECRYPT) > 0) rc = SQLITE_ERROR;
762+
if((sqlcipher_get_test_flags() & TEST_FAIL_DECRYPT) > 0) rc = SQLITE_ERROR;
738763
#endif
739764
if(rc != SQLITE_OK) { /* clear results of failed cipher operation and set error */
740765
sqlcipher_memset((unsigned char*)buffer+offset, 0, page_sz-offset);

src/crypto.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,11 @@ static int cipher_isHex(const unsigned char *hex, int sz){
193193

194194
/* possible flags for simulating specific test conditions */
195195
#ifdef SQLCIPHER_TEST
196-
#define TEST_FAIL_NEXT_ENCRYPT (1ul << 0) /* 1 */
197-
#define TEST_FAIL_NEXT_DECRYPT (1ul << 1) /* 2 */
198-
int sqlcipher_get_test_flags(void);
199-
void sqlcipher_set_test_flags(int);
196+
#define TEST_FAIL_ENCRYPT 0x01
197+
#define TEST_FAIL_DECRYPT 0x02
198+
#define TEST_FAIL_MIGRATE 0x04
199+
unsigned int sqlcipher_get_test_flags(void);
200+
void sqlcipher_set_test_flags(unsigned int);
200201
#endif
201202

202203
/* extensions defined in crypto_impl.c */

src/crypto_impl.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@
4545
#endif
4646

4747
#ifdef SQLCIPHER_TEST
48-
static volatile int cipher_test_flags = 0;
48+
static volatile unsigned int cipher_test_flags = 0;
49+
unsigned int sqlcipher_get_test_flags() {
50+
return cipher_test_flags;
51+
}
52+
void sqlcipher_set_test_flags(unsigned int flags) {
53+
cipher_test_flags = flags;
54+
}
4955
#endif
5056

5157
/* Generate code to return a string value */
@@ -402,16 +408,6 @@ char* sqlcipher_version() {
402408
return version;
403409
}
404410

405-
#ifdef SQLCIPHER_TEST
406-
int sqlcipher_get_test_flags() {
407-
return cipher_test_flags;
408-
}
409-
410-
void sqlcipher_set_test_flags(int flags) {
411-
cipher_test_flags = flags;
412-
}
413-
#endif
414-
415411
/**
416412
* Initialize new cipher_ctx struct. This function will allocate memory
417413
* for the cipher context and for the key
@@ -1380,7 +1376,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
13801376
pass = sqlcipher_malloc(pass_sz+1);
13811377
memset(pass, 0, pass_sz+1);
13821378
memcpy(pass, ctx->read_ctx->pass, pass_sz);
1383-
1379+
13841380
/* Version 4 - current, no upgrade required, so exit immediately */
13851381
rc = sqlcipher_check_connection(db_filename, pass, pass_sz, "", &user_version, &journal_mode);
13861382
if(rc == SQLITE_OK){
@@ -1398,6 +1394,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
13981394
if(pragma_compat) sqlcipher_free(pragma_compat, sqlite3Strlen30(pragma_compat));
13991395
pragma_compat = NULL;
14001396
}
1397+
14011398
/* if we exit the loop normally we failed to determine the version, this is an error */
14021399
CODEC_TRACE("Upgrade format not determined\n");
14031400
goto handle_error;
@@ -1445,6 +1442,14 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
14451442
goto handle_error;
14461443
}
14471444

1445+
#ifdef SQLCIPHER_TEST
1446+
if((sqlcipher_get_test_flags() & TEST_FAIL_MIGRATE) > 0) {
1447+
rc = SQLITE_ERROR;
1448+
CODEC_TRACE("simulated migrate failure, error code %d\n", rc);
1449+
goto handle_error;
1450+
}
1451+
#endif
1452+
14481453
rc = sqlite3_exec(db, set_user_version, NULL, NULL, NULL);
14491454
if(rc != SQLITE_OK){
14501455
CODEC_TRACE("set user version failed, error code %d\n", rc);
@@ -1537,7 +1542,6 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
15371542

15381543
handle_error:
15391544
CODEC_TRACE("An error occurred attempting to migrate the database - last error %d\n", rc);
1540-
rc = SQLITE_ERROR;
15411545

15421546
cleanup:
15431547
if(pass) sqlcipher_free(pass, pass_sz);

test/sqlcipher-codecerror.test

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ do_test codec-error-journal-delete {
6666

6767
catchsql {
6868
PRAGMA key = 'testkey';
69-
PRAGMA cipher_test = fail_next_encrypt;
69+
PRAGMA cipher_test_on = fail_encrypt;
7070
UPDATE t1 SET b = 'fail' WHERE a = 5000;
7171
}
7272

7373
db close
7474
sqlite_orig db test.db
7575

7676
execsql {
77-
PRAGMA cipher_test = fail_next_encrypt;
77+
PRAGMA cipher_test_off = fail_encrypt;
7878
PRAGMA key = 'testkey';
7979
PRAGMA cipher_integrity_check;
8080
PRAGMA integrity_check;
@@ -92,15 +92,15 @@ do_test codec-error-journal-wal {
9292

9393
catchsql {
9494
PRAGMA key = 'testkey';
95-
PRAGMA cipher_test = fail_next_encrypt;
95+
PRAGMA cipher_test_on = fail_encrypt;
9696
UPDATE t1 SET b = 'fail' WHERE a = 5000;
9797
}
9898

9999
db close
100100
sqlite_orig db test.db
101101

102102
execsql {
103-
PRAGMA cipher_test = fail_next_encrypt;
103+
PRAGMA cipher_test_off = fail_encrypt;
104104
PRAGMA key = 'testkey';
105105
PRAGMA cipher_integrity_check;
106106
PRAGMA integrity_check;
@@ -120,7 +120,7 @@ do_test codec-error-journal-wal-transaction {
120120
PRAGMA key = 'testkey';
121121
BEGIN;
122122
UPDATE t1 SET b = 'success' WHERE a = 1;
123-
PRAGMA cipher_test = fail_next_encrypt;
123+
PRAGMA cipher_test_on = fail_encrypt;
124124
UPDATE t1 SET b = 'fail' WHERE a = 5000;
125125
COMMIT;
126126
}
@@ -129,7 +129,7 @@ do_test codec-error-journal-wal-transaction {
129129
sqlite_orig db test.db
130130

131131
execsql {
132-
PRAGMA cipher_test = fail_next_encrypt;
132+
PRAGMA cipher_test_off = fail_encrypt;
133133
PRAGMA key = 'testkey';
134134
PRAGMA cipher_integrity_check;
135135
PRAGMA integrity_check;
@@ -149,15 +149,15 @@ do_test codec-error-journal-wal-read {
149149
catchsql {
150150
PRAGMA key = 'testkey';
151151
SELECT count(*) FROM sqlite_schema;
152-
PRAGMA cipher_test = fail_next_decrypt;
152+
PRAGMA cipher_test_on = fail_decrypt;
153153
UPDATE t1 SET b = 'fail' WHERE a = 5000;
154154
}
155155

156156
db close
157157
sqlite_orig db test.db
158158

159159
execsql {
160-
PRAGMA cipher_test = fail_next_decrypt;
160+
PRAGMA cipher_test_off = fail_decrypt;
161161
PRAGMA key = 'testkey';
162162
PRAGMA cipher_integrity_check;
163163
PRAGMA integrity_check;

test/sqlcipher-compatibility.test

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -360,22 +360,23 @@ file delete -force test.db
360360

361361
# open a 1.1.8 database without hmac, then copy the data
362362
do_test attach-and-copy-1.1.8 {
363-
sqlite_orig db $sampleDir/sqlcipher-1.1.8-testkey.db
363+
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db test.db
364+
sqlite_orig db test.db
364365

365366
execsql {
366367
PRAGMA key = 'testkey';
367368
PRAGMA cipher_use_hmac = OFF;
368369
PRAGMA kdf_iter = 4000;
369370
PRAGMA cipher_page_size = 1024;
370371
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
371-
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey-hmac';
372+
ATTACH DATABASE 'test-new.db' AS db2 KEY 'testkey-hmac';
372373
CREATE TABLE db2.t1(a,b);
373374
INSERT INTO db2.t1 SELECT * FROM main.t1;
374375
DETACH DATABASE db2;
375376
}
376377
db close
377378

378-
sqlite_orig db test.db
379+
sqlite_orig db test-new.db
379380
execsql {
380381
PRAGMA key = 'testkey-hmac';
381382
SELECT count(*) FROM t1;
@@ -384,7 +385,7 @@ do_test attach-and-copy-1.1.8 {
384385
} {ok 75709 1 1 one one 1 2 one two 1 2}
385386
db close
386387
file delete -force test.db
387-
388+
file delete -force test-new.db
388389

389390
# open a standard database, then attach a new
390391
# database with completely different options.
@@ -681,7 +682,7 @@ file delete -force test-vacuum.db
681682
# setting as the original
682683
do_test default-hmac-kdf-attach {
683684
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db test.db
684-
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db sqlcipher-1.1.8-testkey.db;
685+
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db sqlcipher-1.1.8-testkey.db
685686
sqlite_orig db test.db
686687
execsql {
687688
PRAGMA cipher_default_use_hmac = OFF;
@@ -707,7 +708,7 @@ file delete -force sqlcipher-1.1.8-testkey.db
707708
# fail because the hmac setting for the
708709
# attached database is not compatible
709710
do_test attach-1.1.8-database-from-2.0-fails {
710-
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db sqlcipher-1.1.8-testkey.db;
711+
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db sqlcipher-1.1.8-testkey.db
711712
sqlite_orig db test.db
712713
catchsql {
713714
PRAGMA key = 'testkey';
@@ -725,7 +726,7 @@ file delete -force sqlcipher-1.1.8-testkey.db
725726
# succeed now that hmac is off by default
726727
# before the attach
727728
do_test change-default-hmac-kdf-attach {
728-
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db sqlcipher-1.1.8-testkey.db;
729+
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db sqlcipher-1.1.8-testkey.db
729730
sqlite_orig db test.db
730731
execsql {
731732
PRAGMA key = 'testkey';
@@ -1087,19 +1088,22 @@ file delete -force test.db test.db-migrated test.db-journal
10871088
do_test migrate-3-0-database-to-current-format {
10881089
file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
10891090
sqlite_orig db test.db
1090-
execsql {
1091+
set rc {}
1092+
1093+
lappend rc [execsql {
10911094
PRAGMA key = 'testkey';
10921095
PRAGMA cipher_migrate;
1093-
}
1096+
SELECT count(*) FROM sqlite_schema;
1097+
}]
10941098
db close
10951099

10961100
sqlite_orig db test.db
1097-
execsql {
1101+
lappend rc [execsql {
10981102
PRAGMA key = 'testkey';
10991103
SELECT count(*) FROM sqlite_schema;
11001104
PRAGMA journal_mode;
1101-
}
1102-
} {ok 1 delete}
1105+
}]
1106+
} {{ok 0 1} {ok 1 delete}}
11031107
db close
11041108
file delete -force test.db
11051109

@@ -1133,6 +1137,58 @@ do_test migrate-wal-database-to-current {
11331137
db close
11341138
file delete -force test.db
11351139

1140+
# test original database is left untouched after
1141+
# a failed migration e.g. due to low disk space
1142+
do_test migrate-failure {
1143+
file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
1144+
sqlite_orig db test.db
1145+
1146+
set rc {}
1147+
1148+
lappend rc [execsql {
1149+
PRAGMA key = 'testkey';
1150+
PRAGMA cipher_test_on = fail_migrate;
1151+
PRAGMA cipher_migrate;
1152+
}]
1153+
db close
1154+
1155+
sqlite_orig db test.db
1156+
lappend rc [execsql {
1157+
PRAGMA key = 'testkey';
1158+
PRAGMA cipher_test_off = fail_migrate;
1159+
PRAGMA cipher_compatibility = 3;
1160+
SELECT count(*) FROM sqlite_schema;
1161+
}]
1162+
} {{ok 1} {ok 1}}
1163+
db close
1164+
file delete -force test.db test.db-migrated
1165+
1166+
# leave database is a readable state after a
1167+
# a failed migration
1168+
do_test migrate-failure-readable {
1169+
file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
1170+
sqlite_orig db test.db
1171+
1172+
set rc {}
1173+
lappend rc [execsql {
1174+
PRAGMA key = 'testkey';
1175+
PRAGMA cipher_test_on = fail_migrate;
1176+
PRAGMA cipher_migrate;
1177+
}]
1178+
1179+
lappend rc [catchsql {
1180+
SELECT count(*) FROM sqlite_schema;
1181+
}]
1182+
db close
1183+
1184+
sqlite_orig db test.db
1185+
lappend rc [execsql {
1186+
PRAGMA cipher_test_off = fail_migrate;
1187+
PRAGMA cipher_test;
1188+
}]
1189+
} {{ok 1} {1 {SQL logic error}} 0}
1190+
db close
1191+
file delete -force test.db test.db-migrated
11361192

11371193
do_test key-database-by-name {
11381194
sqlite_orig db test.db
@@ -1259,6 +1315,7 @@ do_test can-migrate-with-raw-hex-key {
12591315
PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
12601316
PRAGMA cipher_migrate;
12611317
}
1318+
db close
12621319

12631320
sqlite_orig db test.db
12641321
execsql {

0 commit comments

Comments
 (0)