2 // OCSPCacheUpgradeTests.m
7 #include <AssertMacros.h>
8 #import <XCTest/XCTest.h>
9 #import <Security/SecCertificatePriv.h>
10 #include <utilities/SecCFWrappers.h>
12 #import "trust/trustd/SecOCSPRequest.h"
13 #import "trust/trustd/SecOCSPResponse.h"
14 #import "trust/trustd/SecOCSPCache.h"
16 #import "TrustDaemonTestCase.h"
17 #import "OCSPCacheTests_data.h"
19 @interface OCSPCacheTests : TrustDaemonTestCase
22 @implementation OCSPCacheTests
26 /* Delete the OCSP cache DB so we can start fresh */
27 SecOCSPCacheDeleteCache();
32 SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _leaf_cert, sizeof(_leaf_cert));
33 SecCertificateRef issuer = SecCertificateCreateWithBytes(NULL, _issuer, sizeof(_issuer));
34 SecOCSPRequestRef request = SecOCSPRequestCreate(leaf, issuer);
35 SecOCSPResponseRef response = SecOCSPCacheCopyMatching(request, NULL);
37 CFReleaseNull(issuer);
38 SecOCSPRequestFinalize(request);
41 SecOCSPResponseFinalize(response);
47 - (void)writeResponse1ToDB
49 NSData *responseData = [NSData dataWithBytes:_ocsp_response1 length:sizeof(_ocsp_response1)];
50 SecOCSPResponseRef response = SecOCSPResponseCreate((__bridge CFDataRef)responseData);
51 /* use a verifyTime within the validity of the ocsp response */
52 (void)SecOCSPResponseCalculateValidity(response, 0, 60, 595602000.0); // as a side effect, populates the expire time
53 SecOCSPCacheReplaceResponse(NULL, response, NULL, 595602000.0);
54 SecOCSPResponseFinalize(response);
57 - (void)writeResponse2ToDB
59 NSData *responseData = [NSData dataWithBytes:_ocsp_response2 length:sizeof(_ocsp_response2)];
60 SecOCSPResponseRef response = SecOCSPResponseCreate((__bridge CFDataRef)responseData);
61 (void)SecOCSPResponseCalculateValidity(response, 0, 60, 596180000.0); // as a side effect, populates the expire time
62 SecOCSPCacheReplaceResponse(NULL, response, NULL,596180000.0);
63 SecOCSPResponseFinalize(response);
66 - (void)replaceResponse
68 NSData *responseData = [NSData dataWithBytes:_ocsp_response1 length:sizeof(_ocsp_response1)];
69 SecOCSPResponseRef response1 = SecOCSPResponseCreate((__bridge CFDataRef)responseData);
70 (void)SecOCSPResponseCalculateValidity(response1, 0, 60, 595602000.0); // populate the expire time
72 responseData = [NSData dataWithBytes:_ocsp_response2 length:sizeof(_ocsp_response2)];
73 SecOCSPResponseRef response2 = SecOCSPResponseCreate((__bridge CFDataRef)responseData);
74 (void)SecOCSPResponseCalculateValidity(response2, 0, 60, 596180000.0); // populate the expire time
76 SecOCSPCacheReplaceResponse(response1, response2, NULL, 596180000.0);
77 SecOCSPResponseFinalize(response1);
78 SecOCSPResponseFinalize(response2);
81 - (void)createDBFromSQL:(NSString *)sql
83 CFStringRef cf_path = SecOCSPCacheCopyPath();
84 CFStringPerformWithCString(cf_path, ^(const char *path) {
85 /* Create ocsp cahche */
87 XCTAssertEqual(sqlite3_open(path, &db), SQLITE_OK, "create ocsp cache");
88 XCTAssertEqual(sqlite3_exec(db, [sql cStringUsingEncoding:NSUTF8StringEncoding], NULL, NULL, NULL), SQLITE_OK,
89 "populate ocsp cache");
90 XCTAssertEqual(sqlite3_close_v2(db), SQLITE_OK);
93 CFReleaseNull(cf_path);
98 CFStringRef cf_path = SecOCSPCacheCopyPath();
99 __block int result = 0;
100 CFStringPerformWithCString(cf_path, ^(const char *path) {
102 sqlite3_stmt *stmt = NULL;
103 XCTAssertEqual(sqlite3_open(path, &db), SQLITE_OK);
104 NSString *countResponses = @"SELECT COUNT(responseId) FROM responses;";
105 XCTAssertEqual(sqlite3_prepare_v2(db, [countResponses cStringUsingEncoding:NSUTF8StringEncoding],
106 (int)[countResponses length], &stmt, NULL),
108 XCTAssertEqual(sqlite3_step(stmt), SQLITE_ROW);
109 result = sqlite3_column_int(stmt, 0);
110 XCTAssertEqual(sqlite3_finalize(stmt), SQLITE_OK);
111 XCTAssertEqual(sqlite3_close_v2(db), SQLITE_OK);
113 CFReleaseNull(cf_path);
117 - (void)testNewDatabase
119 [self writeResponse1ToDB];
120 XCTAssert([self canReadDB]);
123 - (void)testNewDatabaseReOpen
125 [self writeResponse1ToDB];
126 XCTAssert([self canReadDB]);
127 SecOCSPCacheCloseDB();
128 XCTAssert([self canReadDB]);
129 [self replaceResponse];
130 XCTAssert([self canReadDB]);
133 - (void)testOldDatabaseUpgradeNoContent
135 [self createDBFromSQL:_oldDBSchema];
136 [self writeResponse1ToDB];
137 XCTAssert([self canReadDB]);
140 - (void)testOldDatabaseUpgradeWithContent
142 [self createDBFromSQL:_oldDBSchemaWithContent];
143 XCTAssert([self canReadDB]);
144 [self replaceResponse];
145 XCTAssert([self canReadDB]);
148 - (void)testUpgradedDatabaseNoContent
150 [self createDBFromSQL:_oldDBSchema];
151 XCTAssertFalse([self canReadDB]); // should upgrade the DB
152 SecOCSPCacheCloseDB();
153 [self writeResponse1ToDB];
154 XCTAssert([self canReadDB]);
157 - (void)testUpgradedDatabaseWithContent
159 [self createDBFromSQL:_oldDBSchemaWithContent];
160 XCTAssert([self canReadDB]); // should upgrade the DB
161 SecOCSPCacheCloseDB();
162 [self replaceResponse];
163 XCTAssert([self canReadDB]);
166 - (void)testGCExpiredResponses
168 [self createDBFromSQL:_oldDBSchemaWithContent]; // since this is an old schema, the certStatus will be CS_NotParsed
169 /* don't replace response 1, just add response 2 a week after response 1 expired */
170 [self writeResponse2ToDB]; // as a side effect, should GC the expired non-revoked response
171 SecOCSPCacheCloseDB();
172 XCTAssertEqual([self countEntries], 1);
175 - (void)testNoGCExpiredRevokedResponses
177 [self writeResponse1ToDB];
178 /* don't replace response 1, just add response 2 a week after response 1 expired */
179 [self writeResponse2ToDB]; // should not GC the expired revoked response 1
180 SecOCSPCacheCloseDB();
181 XCTAssertEqual([self countEntries], 2);