rl.c
10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#include <PR/bcp.h>
#include <PR/bbboot.h>
#include <PR/bbnand.h>
#include <PR/bbticket.h>
#include <PR/bbvirage.h>
#include <PR/bbcert.h>
#include <PR/bbskapi.h>
#include "util.h"
#include "skerror.h"
#include "cert.h"
#include "rl.h"
extern BbRsaPublicKey4096 gRootKey;
extern BbRsaExponent gRootExp;
int getInternalRlVersion(u32 rlType, u32 *version)
{
switch(rlType){
case BB_CRL_TYPE_XS:
*version = v01.tsCrlVersion;
return SK_SUCCESS;
case BB_CRL_TYPE_CP:
*version = v01.cpCrlVersion;
return SK_SUCCESS;
case BB_CRL_TYPE_CA:
*version = v01.caCrlVersion;
return SK_SUCCESS;
}
return SK_FAIL;
}
int consistentRlNaming(BbCrlHead *head,u32 rlType)
{
if(head->type != rlType)
return SK_FAIL;
switch(rlType){
case BB_CRL_TYPE_XS:
if(strncmp(head->issuer,BB_CERT_STR_XSCA_CHAIN,9))
return SK_FAIL;
break;
case BB_CRL_TYPE_CP:
if(strncmp(head->issuer,BB_CERT_STR_CPCA_CHAIN,9))
return SK_FAIL;
break;
case BB_CRL_TYPE_CA:
if(strncmp(head->issuer,BB_CERT_STR_ROOT,5))
return SK_FAIL;
break;
default:
return SK_FAIL;
}
return SK_SUCCESS;
}
int updateRl(BbCrlBundle *rl)
{
switch(rl->head->type){
case BB_CRL_TYPE_XS:
if(rl->head->versionNumber > (u32)v01.tsCrlVersion)
v01.tsCrlVersion = (u8)rl->head->versionNumber;
else
return SK_SUCCESS;
break;
case BB_CRL_TYPE_CP:
if(rl->head->versionNumber > (u32)v01.cpCrlVersion)
v01.cpCrlVersion = (u8)rl->head->versionNumber;
else
return SK_SUCCESS;
break;
case BB_CRL_TYPE_CA:
if(rl->head->versionNumber > (u32)v01.caCrlVersion){
v01.caCrlVersion = (u8)rl->head->versionNumber;
/* and all others go to zero */
v01.cpCrlVersion = 0;
v01.contentRlVersion = 0;
v01.tsCrlVersion = 0;
}
else
return SK_SUCCESS;
break;
default:
/* can't really get here since type hardcoded in rl.c earlier
* in callstack. leaving to catch coding bug of wrong type.
*/
return SK_FAIL;
}
if(v01Update(&v01) != SK_SUCCESS){
message("updateRl(): v01Update Fail.\n");
return SK_FAIL;
}
return SK_SUCCESS;
}
/* it would be nice to only obtain the rl type from the rl arg,
* but we could get spoofed when interpretting versionNumber==0
* as having no rl for this type (by the sysapp providing the
* wrong type, leading to another lists v012Version coming back
* for comparison).
*/
int validateRl(BbCrlBundle *rl, u32 rlType, u32 ticketVersion)
{
u32 v01Version;
SkDataChain dataChain[2];
u32 chainType = CHAIN_TYPE_DONT_CARE;
int ret;
if(getInternalRlVersion(rlType,&v01Version)!=SK_SUCCESS){
/* should never fail since rlType hard-coded in calls to
* validateRl. leaving just to catch coding errors.
*/
return SK_FAIL;
}
if(rl->head==0){
if(v01Version==0){
/* a NULL head implies nothing revoked. OK as long as internal
* version is 0.
*/
if(ticketVersion>0){
/* no internal counter update since ticket not verified.
* do not want bogus ticket to prevent future sysapp launch!
*/
return SK_FAIL;
}
return SK_SUCCESS;
}
else{
return SK_FAIL;
}
}
if(v01Version > rl->head->versionNumber
|| ticketVersion > rl->head->versionNumber){
/* no internal counter update for ticketVersion clause since
* ticket not verified
*/
return SK_FAIL;
}
if(consistentRlNaming(rl->head,rlType) != SK_SUCCESS){
return SK_FAIL;
}
/* verify chain, but no chain for carl since root signed */
if(rlType != BB_CRL_TYPE_CA){
switch(rlType){
case BB_CRL_TYPE_XS:
chainType = CHAIN_TYPE_TICKET_PUB;
break;
case BB_CRL_TYPE_CP:
chainType = CHAIN_TYPE_CONTENT_PUB;
break;
default:
return SK_FAIL;
}
if(verifyCertChain(rl->certChain, chainType) != SK_SUCCESS){
return SK_FAIL;
}
}
/* check signature */
dataChain[0].data = (u8 *)(rl->head)+sizeof(rl->head->signature);
dataChain[0].size = sizeof(BbCrlHead) - sizeof(rl->head->signature);
dataChain[1].data = (u8 *)rl->list;
dataChain[1].size = rl->head->numberRevoked * sizeof(BbCrlEntry);
if(strcmp(rl->head->issuer,BB_CERT_STR_ROOT) == 0) {
ret = verifyRsaSigDataChain(dataChain,2,(u32 *)gRootKey,gRootExp,
BB_SIG_TYPE_RSA4096, &(rl->head->signature));
}
else{
ret = verifyRsaSigDataChain(dataChain, 2,
(u32 *)(((BbRsaCert *)(rl->certChain[0]))->publicKey),
((BbRsaCert *)(rl->certChain[0]))->exponent,
rl->head->sigType,
&(rl->head->signature));
}
if(ret!=SK_SUCCESS)
return ret;
return updateRl(rl);
}
/* if tsrlVersion is -1, ignore tsrl */
int validateRls(BbCrlBundle *carl, int carlVersion,
BbCrlBundle *cprl, int cprlVersion,
BbCrlBundle *tsrl, int tsrlVersion)
{
int i;
/* NOTE: only want to update v01 for valid RL. since validation
* dependencies exist (i.e., tsrl, cprl and crl depend on
* carl), and since the occurence of v01 rl updates must be low
* (we only have 8 bits for version), easiest to v01 update one
* rl at a time as we go. the update occurs in validateRl().
*/
/* is CARL valid? */
if(validateRl(carl, BB_CRL_TYPE_CA, carlVersion) != SK_SUCCESS)
return SK_API_INVALID_CARL;
/* for all CARL entries, are there any certs in chains for:
* - cprl
* - tsrl
* if so, FAIL.
*/
if(RL_EXISTS(*carl)){
for(i=0; i<carl->head->numberRevoked; i++){
if(strstr(cprl->certChain[0]->name.server, carl->list[i])!=NULL)
return SK_API_REVOKED_SERVER;
if(tsrlVersion >= 0 &&
strstr(tsrl->certChain[0]->name.server, carl->list[i])!=NULL)
return SK_API_REVOKED_SERVER;
}
}
/* is CPRL valid? */
if(validateRl(cprl, BB_CRL_TYPE_CP, cprlVersion) != SK_SUCCESS)
return SK_API_INVALID_CPRL;
/* is TSRL valid? */
if(tsrlVersion>=0 && (validateRl(tsrl, BB_CRL_TYPE_XS, tsrlVersion)
!= SK_SUCCESS))
return SK_API_INVALID_TSRL;
return SK_SUCCESS;
}
/*
* return SK_API failure codes if revoked. otherwise SK_SUCCESS.
*/
int ticketBundleRevoked(BbTicketBundle *ticketBundle,
BbAppLaunchCrls *crls)
{
int ret,i;
if(!rlPtrsValid(crls))
return SK_API_FAIL;
/* first check the rls themselves (will update v01 as needed) */
ret = validateRls(&crls->carl,ticketBundle->ticket->cmd.head.caCrlVersion,
&crls->cprl,ticketBundle->ticket->cmd.head.cpCrlVersion,
&crls->tsrl,ticketBundle->ticket->head.tsCrlVersion);
if(ret != SK_SUCCESS)
return ret;
/* now check the ticket and cmd chains */
if(RL_EXISTS(crls->carl)){
for(i=0; i<crls->carl.head->numberRevoked; i++){
if(strstr(ticketBundle->ticketChain[1]->name.server,
crls->carl.list[i])!=NULL)
return SK_API_REVOKED_SERVER;
if(strstr(ticketBundle->cmdChain[1]->name.server,
crls->carl.list[i])!=NULL)
return SK_API_REVOKED_SERVER;
}
}
if(RL_EXISTS(crls->cprl)){
for(i=0; i<crls->cprl.head->numberRevoked; i++){
if(strstr(ticketBundle->cmdChain[0]->name.server,
crls->cprl.list[i])!=NULL)
return SK_API_REVOKED_SERVER;
}
}
if(RL_EXISTS(crls->tsrl)){
for(i=0; i<crls->tsrl.head->numberRevoked; i++){
if(strstr(ticketBundle->ticketChain[0]->name.server,
crls->tsrl.list[i])!=NULL)
return SK_API_REVOKED_SERVER;
}
}
return SK_API_SUCCESS;
}
/* NOTE: don't use crls->tsrl here. */
int sysappBundleRevoked(BbContentMetaDataHead *cmdh,
BbCertBase **cmdChain,
BbAppLaunchCrls *crls)
{
int i, ret;
/* check the rl bundle ptrs here in sysapp case */
if(RL_EXISTS(crls->carl)){
if(!bundlePtrValid(crls->carl.head, sizeof *crls->carl.head, 4))
return SK_FAIL;
if(!bundlePtrValid(crls->carl.list,
sizeof(BbCrlEntry)*crls->carl.head->numberRevoked, 4))
return SK_FAIL;
}
if(RL_EXISTS(crls->cprl)){
if(!bundlePtrValid(crls->cprl.head, sizeof *crls->cprl.head, 4))
return SK_FAIL;
if(!bundlePtrValid(crls->cprl.list,
sizeof(BbCrlEntry)*crls->cprl.head->numberRevoked, 4))
return SK_FAIL;
if(!bundlePtrValid(crls->cprl.certChain,4,4))
return SK_FAIL;
if(!bundlePtrValid(crls->cprl.certChain[0],sizeof(BbRsaCert),4))
return SK_FAIL;
}
/* first check the rls themselves (will update v01 as needed) */
ret = validateRls(&crls->carl, cmdh->caCrlVersion,
&crls->cprl, cmdh->cpCrlVersion,
&crls->tsrl, -1);
if(ret != SK_SUCCESS)
return ret;
/* now check the cmd chains */
if(RL_EXISTS(crls->carl)){
for(i=0; i<crls->carl.head->numberRevoked; i++){
if(strstr(cmdChain[1]->name.server, crls->carl.list[i])!=NULL)
return SK_API_REVOKED_SERVER;
}
}
if(RL_EXISTS(crls->cprl)){
for(i=0; i<crls->cprl.head->numberRevoked; i++){
if(strstr(cmdChain[0]->name.server, crls->cprl.list[i])!=NULL)
return SK_API_REVOKED_SERVER;
}
}
return SK_API_SUCCESS;
}
int rlPtrsValid(BbAppLaunchCrls *crls)
{
BbCrlBundle *rl;
int i;
for(i=0, rl=(BbCrlBundle *)crls;
i<sizeof(BbAppLaunchCrls)/sizeof(BbCrlBundle);
i++, rl++){
if(!RL_EXISTS(*rl))
continue;
if(!ptrValid(rl->head, sizeof *rl->head, 4))
return 0;
if(!ptrValid(rl->list, sizeof(BbCrlEntry)*rl->head->numberRevoked, 4))
return 0;
if(rl->head->type!=BB_CRL_TYPE_CA &&
!certChainPtrsValid(rl->certChain)){
return 0;
}
}
return 1;
}