1=== Advanced CFErrorRef usage ===
2
3Make SecError a macro with an extra argument (formatOptions) and make the arguments proper CFStringRef
4CFCopyDescription takes formatOptions as well, which it passes down to us.
5Make sure we plumb though formatOptions everywhere
6Have every cftype implement a proper copyDescriotion function that looks at a kSecDebugFormatOption key and use it to do debug printing.
7Have 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
28SSL EKU:
29Test ssl server and ssl client against certs with proper and wrong EKU.  Also
30test this for EV certs.
31IPSEC EKU:
32Add some ipsec certs with proper ipsec eku extensions and without them and
33ensure that the ipsec policy rejects (done in si-20-sectrust) and accepts
34each kind as it should.
35
36== AUDIT of securityd_server_request ==
37
38in_args are a valid plist.
39
40sec_item_add_id
41    _SecItemAdd() argument 1 is a dictionary, but its contents have not been checked.
42sec_item_copy_matching_id
43    _SecItemCopyMatching() argument 1 is a dictionary, but its contents have not been checked.
44sec_item_delete_id
45    _SecItemDelete() argument 1 is a dictionary, but its contents have not been checked.
46sec_item_update_id
47    _SecItemUpdate() argument 1 and 2 are dictionaries, but their contents have not been checked.
48sec_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).
51sec_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.
54sec_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.
56sec_delete_all_id (ok)
57    Audit done (args_in not used and its value is ignored).
58sec_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.
62sec_restore_keychain (ok)
63    Audit done (args_in not used and its value is ignored).
64
65== GENERAL ==
66
67Function naming conventions:
68 - Use Sec@@@Finalaize only if the function does not free the thing it's finalizing.
69 - use Sec@@@Destroy otherwise.
70
71Move EVRoots.plist and system TrustStore.sqlite3 into perfect hashtable inside securityd.
72
73Stop using framework relative resources in securityd since it uses a few kb of ram just to get to them.
74
75Change the interfaces to securityd to use real argument lists and do all the encoding/decoding inside client.c and server.c.
76
77Remove SecCertificateCreate() now that <rdar://problem/5701851> iap submits a binary is fixed.
78
79SecKeyRawSign/SecKeyRawVerify should get better error codes.
80
81== OCSP ==
82
83Consider calling int sqlite3_release_memory(int); (after committing outstanding transactions); when we are low on ram.
84
85change 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
87When receiving a stale response refetch by adding a Cache-Control: no-cache header.
88Implement a timeout and retry count (perhaps after timeout go to next responder, but possibly retry responders again if they all timeout).
89If 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
91Verify responder cert chain. (done)
92Verify singleResponse validity at usage time. (done)
93Verify signature of response. (done)
94Verify responder id. (done)
95
96== SSL Policy ==
97
98Check extended keyUsage and keyUsage of leaf.
99
100== Snowbird ==
101
102Priority 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
128Notes 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
159To adopt libdispatch in SecTrustServer.c, we should make a queue per builder.
160That builders queue can then have
161The 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 */
202typedef struct state_engine_s state_engine_t;
203typedef void(*state_engine_function_t)(void *);
204#ifdef __BLOCKS__
205typedef void(^state_engine_block_t)(void);
206void state_engine_init(state_engine_t *engine, state_engine_block_t completed);
207void state_engine_next(state_engine_t *engine, state_engine_block_t state);
208#endif
209void state_engine_init_f(state_engine_t *engine,
210    void *context, state_engine_function_t completed);
211
212void state_engine_next_f(state_engine_t *engine,
213    void *context, state_engine_function_t state);
214bool state_engine_step(state_engine_t **engine);
215void state_engine_push(state_engine_t **engine, state_engine_t *child);
216
217/* Complete engine, return parent, . */
218state_engine_t *state_engine_pop(state_engine_t *engine);
219
220/* State engine spi */
221struct 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
231void 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
237bool 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
251void state_engine_push(state_engine_t **engine,
252    state_engine_t *child) {
253    child->parent = *engine;
254    *engine = child;
255}
256
257state_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
266