]> git.saurik.com Git - apple/security.git/blob - TODO
Security-57031.20.26.tar.gz
[apple/security.git] / TODO
1 === Advanced CFErrorRef usage ===
2
3 Make SecError a macro with an extra argument (formatOptions) and make the arguments proper CFStringRef
4 CFCopyDescription takes formatOptions as well, which it passes down to us.
5 Make sure we plumb though formatOptions everywhere
6 Have every cftype implement a proper copyDescriotion function that looks at a kSecDebugFormatOption key and use it to do debug printing.
7 Have the CFGiblis macros automatically implement copyDebugDescription function that calls
8
9
10 == Content Protection ==
11
12 * Notice that the system keystore is unavailible during upgrade and
13 fail without removing old keychain since it won't work after an
14 upgrade either.
15
16 * cert table should be AlwaysAvailable + migratable...
17
18 ====
19
20 * security export - dump all classes and caches in unencrypted plist
21 genp, inet, cert, keys, ocsp, cair, crls.
22 security export genp, inet, cert, keys, ocsp, cair
23
24 * security dh command should support decodePEM.
25
26 == TESTCASES ==
27
28 SSL EKU:
29 Test ssl server and ssl client against certs with proper and wrong EKU. Also
30 test this for EV certs.
31 IPSEC EKU:
32 Add some ipsec certs with proper ipsec eku extensions and without them and
33 ensure that the ipsec policy rejects (done in si-20-sectrust) and accepts
34 each kind as it should.
35
36 == AUDIT of securityd_server_request ==
37
38 in_args are a valid plist.
39
40 sec_item_add_id
41 _SecItemAdd() argument 1 is a dictionary, but its contents have not been checked.
42 sec_item_copy_matching_id
43 _SecItemCopyMatching() argument 1 is a dictionary, but its contents have not been checked.
44 sec_item_delete_id
45 _SecItemDelete() argument 1 is a dictionary, but its contents have not been checked.
46 sec_item_update_id
47 _SecItemUpdate() argument 1 and 2 are dictionaries, but their contents have not been checked.
48 sec_trust_store_contains_id (ok)
49 SecTrustStoreForDomainName() argument 1 is a string of any length (might be 0).
50 SecTrustStoreContainsCertificateWithDigest() argument 1 might be NULL, argument 2 is a data of any length (might be 0).
51 sec_trust_store_set_trust_settings_id (ok)
52 SecCertificateCreateWithData() argument 2 is a data of any length (might be 0) (done)
53 _SecTrustStoreSetTrustSettings() argument 1 might be NULL, argument 3 is either NULL, a dictionary or an array, but its contents have not been checked.
54 sec_trust_store_remove_certificate_id (ok)
55 SecTrustStoreRemoveCertificateWithDigest() argument 2 is a data of any length (might be 0) an its bound to a statement in sqlite.
56 sec_delete_all_id (ok)
57 Audit done (args_in not used and its value is ignored).
58 sec_trust_evaluate_id
59 SecTrustServerEvaluateAsync() argument 1 is a dictionary, but its contents have not been checked.
60 The options field of each policy provided ends up in policy->_options unchecked, so every access
61 of policy->_options in SecPolicyServer.c needs to be sanitized.
62 sec_restore_keychain (ok)
63 Audit done (args_in not used and its value is ignored).
64
65 == GENERAL ==
66
67 Function naming conventions:
68 - Use Sec@@@Finalaize only if the function does not free the thing it's finalizing.
69 - use Sec@@@Destroy otherwise.
70
71 Move EVRoots.plist and system TrustStore.sqlite3 into perfect hashtable inside securityd.
72
73 Stop using framework relative resources in securityd since it uses a few kb of ram just to get to them.
74
75 Change the interfaces to securityd to use real argument lists and do all the encoding/decoding inside client.c and server.c.
76
77 Remove SecCertificateCreate() now that <rdar://problem/5701851> iap submits a binary is fixed.
78
79 SecKeyRawSign/SecKeyRawVerify should get better error codes.
80
81 == OCSP ==
82
83 Consider calling int sqlite3_release_memory(int); (after committing outstanding transactions); when we are low on ram.
84
85 change api to asynchttp.h to take 2 arguments, a boolean flag to use http GET is the URL size is less than 256 bytes, two dictionary arguments of header name,values pairs to add to the GET and POST requests. If only GET is present GET will always be used, if only POST is present only POST will be used. If both are present, we use GET only if the URL size is less than 256 bytes and POST otherwise. The callback should have a CFHTTPMessage() argument, which will go away when the callback returns.
86
87 When receiving a stale response refetch by adding a Cache-Control: no-cache header.
88 Implement a timeout and retry count (perhaps after timeout go to next responder, but possibly retry responders again if they all timeout).
89 If id-pkix-ocsp-nocheck is not present in the responder cert, check revocation status of the responder cert itself (probably via crls, otherwise watch out for infinite recursion).
90
91 Verify responder cert chain. (done)
92 Verify singleResponse validity at usage time. (done)
93 Verify signature of response. (done)
94 Verify responder id. (done)
95
96 == SSL Policy ==
97
98 Check extended keyUsage and keyUsage of leaf.
99
100 == Snowbird ==
101
102 Priority 2
103
104 <rdar://problem/4831694> Implement DSA using libGiants
105 <rdar://problem/4831689> Add support for DSA ciphersuites in SecureTransport
106 <rdar://problem/4831710> Implement DSS (DSA) Support for SecKeys
107 <rdar://problem/4831700> Add support for DSS (DSA) signed certificates
108
109 <rdar://problem/4831731> Support CRL Fetching and caching
110 <rdar://problem/4831751> Support URL based certificate issuer fetching
111
112 <rdar://problem/4831794> Suite B support for Blackberry feature parody
113
114 == ==
115
116 * Trust settings dialog (P2 for P3)
117 * Trust settings ui (P2 for P3)
118
119 === Later ===
120
121 * SecItemDelete for identities should be server-side so it's done in an exclusive transaction
122
123 * SecKeyRef for DH public/private keys (P3)
124 * AES support
125 - SecKey AES support?
126
127
128 Notes on TrustStore trustsettings db.
129
130 // Version table has one record
131 CREATE TABLE version(version INTEGER);
132 CREATE TABLE cert{sha1 BLOB(20) UNIQUE PRIMARY KEY,subj BLOB,cert BLOB,mdat REAL);
133 CREATE INDEX isubj ON cert(subj);
134 CREATE TABLE trust(sha1 BLOB(20) UNIQUE PRIMARY KEY,
135 domain INTEGER,
136 policy BLOB,
137 application BLOB,
138 keyUsage INTEGER(4),
139 policyString TEXT,
140 allowedError INTEGER,
141 result INTEGER(1)
142 )
143
144 SELECT domain,policyString,allowedError,result FROM trust WHERE
145 (sha1=? OR sha1=defaut) AND
146 domain=? AND
147 (policy=? OR policy ISNULL) AND
148 (application=? OR application ISNULL) AND
149 (keyUsage&?)
150 ORDER BY COLLATE domain DESC;
151
152 BEGIN EXCLUSIVE;
153 INSERT OR REPLACE INTO cert(sha1,subj,cert,mdat)VALUES(?,?,?,?);
154 DELETE FROM trust WHERE sha1=? AND domain=?
155 INSERT INTO trust(sha1,domain,
156 policy,application,keyUsage,policyString,allowedError,result)
157 VALUES(?,?,?,?,?,?,?,?);
158
159 To adopt libdispatch in SecTrustServer.c, we should make a queue per builder.
160 That builders queue can then have
161 The chain builder will look something like
162 dispatch_async(queue, builder, SecPathBuilderNext);
163 inside SecPathBuilderNext we dispatch_async(queue, builder, state);
164 where state is whatever the new state to be run is.
165 where today we invoke the client callback and free the builder in
166 SecPathBuilderStep(), that will be replaced by doing it in the level
167 that today sets builder->state to NULL, which of course just doesn't
168 dispatch any new blocks since invoking the callback completes the API.
169 If we want to allow the caller to use dispatch himself (for sending
170 the reply on a reply queue of some kind that can reschedule jobs when
171 a port_notify_send_ok (or whatever it's called) is received.
172 If async io is done it uses a dispatch_source to run (or it can use a
173 plain cfrunloop callback if the callback are low latency). when the
174 async io operation has completed succesfully a callback is invoked,
175 this callback then pushes the new state onto the queue using
176 dispatch_async(queue, builder, builder->state);
177 so the new state runs after we return from the callback.
178
179 IO can be on the global hi priority queue if it's truely async.
180 Since only one runnable job is ever posted on a queue at a time for a
181 given request, all of the job can be run on the high (dispatching new
182 requests) normal (request handeling) and low (signature
183 verification).
184 priority global queues as we see fit.
185 If multiple requests where received, they would end up being
186 executed round robin on a single core, or in parallel on multi core
187 machines, since each request would get queued by the dispatcher as they
188 arrived, and then jobs for the queues would add their next job to the end
189 of the queue behind the other one again.
190
191 During parts of the code where we write to a databsse or read from a
192 database both of which could potentially block, we need to see if
193 sqlite3 has async APIs otherwise we might end up having to serialize all
194 db accesses to a single serial queue, which stops us from taking advantage
195 of the multiple reader / single writer paradigm. We just might have to
196 create a sqlite3 io thread or threads.
197
198 #if 0
199 /* Idea sketch for state_engine to replace SecPathBuilderStep() one. */
200
201 /* State engine api */
202 typedef struct state_engine_s state_engine_t;
203 typedef void(*state_engine_function_t)(void *);
204 #ifdef __BLOCKS__
205 typedef void(^state_engine_block_t)(void);
206 void state_engine_init(state_engine_t *engine, state_engine_block_t completed);
207 void state_engine_next(state_engine_t *engine, state_engine_block_t state);
208 #endif
209 void state_engine_init_f(state_engine_t *engine,
210 void *context, state_engine_function_t completed);
211
212 void state_engine_next_f(state_engine_t *engine,
213 void *context, state_engine_function_t state);
214 bool state_engine_step(state_engine_t **engine);
215 void state_engine_push(state_engine_t **engine, state_engine_t *child);
216
217 /* Complete engine, return parent, . */
218 state_engine_t *state_engine_pop(state_engine_t *engine);
219
220 /* State engine spi */
221 struct state_engine_s {
222 state_engine_t *parent;
223 void *completed;
224 state_engine_function_t completed_f;
225 void *state;
226 state_engine_function_t state_f;
227 };
228
229 //static state_engine_t *current_engine;
230
231 void state_engine_next_f(state_engine_t *engine,
232 void *state, state_engine_function_t state_f) {
233 engine->state_f = state_f;
234 engine->state = state;
235 }
236
237 bool state_engine_step(state_engine_t **engine) {
238 if (!engine)
239 return false;
240 for (;;) {
241 if (!*engine)
242 return false;
243 if (!(*engine)->state_f) {
244 *engine = state_engine_pop(*engine);
245 } else {
246 (*engine)->state_f((*engine)->state);
247 }
248 }
249 }
250
251 void state_engine_push(state_engine_t **engine,
252 state_engine_t *child) {
253 child->parent = *engine;
254 *engine = child;
255 }
256
257 state_engine_t *state_engine_pop(state_engine_t *engine) {
258 state_engine_t *parent = engine->parent;
259 if (engine->completed_f)
260 engine->completed_f(engine->completed);
261
262 return parent;
263 }
264
265 #endif