Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: nss/lib/dev/ckhelper.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/dev/ckhelper.h ('k') | nss/lib/dev/dev.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "pkcs11.h"
6
7 #ifndef DEVM_H
8 #include "devm.h"
9 #endif /* DEVM_H */
10
11 #ifndef CKHELPER_H
12 #include "ckhelper.h"
13 #endif /* CKHELPER_H */
14
15 extern const NSSError NSS_ERROR_DEVICE_ERROR;
16
17 static const CK_BBOOL s_true = CK_TRUE;
18 NSS_IMPLEMENT_DATA const NSSItem
19 g_ck_true = { (CK_VOID_PTR)&s_true, sizeof(s_true) };
20
21 static const CK_BBOOL s_false = CK_FALSE;
22 NSS_IMPLEMENT_DATA const NSSItem
23 g_ck_false = { (CK_VOID_PTR)&s_false, sizeof(s_false) };
24
25 static const CK_OBJECT_CLASS s_class_cert = CKO_CERTIFICATE;
26 NSS_IMPLEMENT_DATA const NSSItem
27 g_ck_class_cert = { (CK_VOID_PTR)&s_class_cert, sizeof(s_class_cert) };
28
29 static const CK_OBJECT_CLASS s_class_pubkey = CKO_PUBLIC_KEY;
30 NSS_IMPLEMENT_DATA const NSSItem
31 g_ck_class_pubkey = { (CK_VOID_PTR)&s_class_pubkey, sizeof(s_class_pubkey) } ;
32
33 static const CK_OBJECT_CLASS s_class_privkey = CKO_PRIVATE_KEY;
34 NSS_IMPLEMENT_DATA const NSSItem
35 g_ck_class_privkey = { (CK_VOID_PTR)&s_class_privkey, sizeof(s_class_privkey ) };
36
37 static PRBool
38 is_string_attribute(
39 CK_ATTRIBUTE_TYPE aType)
40 {
41 PRBool isString;
42 switch (aType) {
43 case CKA_LABEL:
44 case CKA_NSS_EMAIL:
45 isString = PR_TRUE;
46 break;
47 default:
48 isString = PR_FALSE;
49 break;
50 }
51 return isString;
52 }
53
54 NSS_IMPLEMENT PRStatus
55 nssCKObject_GetAttributes(
56 CK_OBJECT_HANDLE object,
57 CK_ATTRIBUTE_PTR obj_template,
58 CK_ULONG count,
59 NSSArena *arenaOpt,
60 nssSession *session,
61 NSSSlot *slot)
62 {
63 nssArenaMark *mark = NULL;
64 CK_SESSION_HANDLE hSession;
65 CK_ULONG i = 0;
66 CK_RV ckrv;
67 PRStatus nssrv;
68 PRBool alloced = PR_FALSE;
69 void *epv = nssSlot_GetCryptokiEPV(slot);
70 hSession = session->handle;
71 if (arenaOpt) {
72 mark = nssArena_Mark(arenaOpt);
73 if (!mark) {
74 goto loser;
75 }
76 }
77 nssSession_EnterMonitor(session);
78 /* XXX kinda hacky, if the storage size is already in the first template
79 * item, then skip the alloc portion
80 */
81 if (obj_template[0].ulValueLen == 0) {
82 /* Get the storage size needed for each attribute */
83 ckrv = CKAPI(epv)->C_GetAttributeValue(hSession,
84 object, obj_template, count);
85 if (ckrv != CKR_OK &&
86 ckrv != CKR_ATTRIBUTE_TYPE_INVALID &&
87 ckrv != CKR_ATTRIBUTE_SENSITIVE) {
88 nssSession_ExitMonitor(session);
89 nss_SetError(NSS_ERROR_DEVICE_ERROR);
90 goto loser;
91 }
92 /* Allocate memory for each attribute. */
93 for (i = 0; i < count; i++) {
94 CK_ULONG ulValueLen = obj_template[i].ulValueLen;
95 if (ulValueLen == 0 || ulValueLen == (CK_ULONG)-1) {
96 obj_template[i].pValue = NULL;
97 obj_template[i].ulValueLen = 0;
98 continue;
99 }
100 if (is_string_attribute(obj_template[i].type)) {
101 ulValueLen++;
102 }
103 obj_template[i].pValue = nss_ZAlloc(arenaOpt, ulValueLen);
104 if (!obj_template[i].pValue) {
105 nssSession_ExitMonitor(session);
106 goto loser;
107 }
108 }
109 alloced = PR_TRUE;
110 }
111 /* Obtain the actual attribute values. */
112 ckrv = CKAPI(epv)->C_GetAttributeValue(hSession,
113 object, obj_template, count);
114 nssSession_ExitMonitor(session);
115 if (ckrv != CKR_OK &&
116 ckrv != CKR_ATTRIBUTE_TYPE_INVALID &&
117 ckrv != CKR_ATTRIBUTE_SENSITIVE) {
118 nss_SetError(NSS_ERROR_DEVICE_ERROR);
119 goto loser;
120 }
121 if (alloced && arenaOpt) {
122 nssrv = nssArena_Unmark(arenaOpt, mark);
123 if (nssrv != PR_SUCCESS) {
124 goto loser;
125 }
126 }
127
128 if (count > 1 && ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
129 (ckrv == CKR_ATTRIBUTE_SENSITIVE))) {
130 /* old tokens would keep the length of '0' and not deal with any
131 * of the attributes we passed. For those tokens read them one at
132 * a time */
133 for (i = 0; i < count; i++) {
134 if ((obj_template[i].ulValueLen == 0) ||
135 (obj_template[i].ulValueLen == -1)) {
136 obj_template[i].ulValueLen = 0;
137 (void)nssCKObject_GetAttributes(object, &obj_template[i], 1,
138 arenaOpt, session, slot);
139 }
140 }
141 }
142 return PR_SUCCESS;
143 loser:
144 if (alloced) {
145 if (arenaOpt) {
146 /* release all arena memory allocated before the failure. */
147 (void)nssArena_Release(arenaOpt, mark);
148 } else {
149 CK_ULONG j;
150 /* free each heap object that was allocated before the failure. */
151 for (j = 0; j < i; j++) {
152 nss_ZFreeIf(obj_template[j].pValue);
153 }
154 }
155 }
156 return PR_FAILURE;
157 }
158
159 NSS_IMPLEMENT PRStatus
160 nssCKObject_GetAttributeItem(
161 CK_OBJECT_HANDLE object,
162 CK_ATTRIBUTE_TYPE attribute,
163 NSSArena *arenaOpt,
164 nssSession *session,
165 NSSSlot *slot,
166 NSSItem *rvItem)
167 {
168 CK_ATTRIBUTE attr = { 0, NULL, 0 };
169 PRStatus nssrv;
170 attr.type = attribute;
171 nssrv = nssCKObject_GetAttributes(object, &attr, 1,
172 arenaOpt, session, slot);
173 if (nssrv != PR_SUCCESS) {
174 return nssrv;
175 }
176 rvItem->data = (void *)attr.pValue;
177 rvItem->size = (PRUint32)attr.ulValueLen;
178 return PR_SUCCESS;
179 }
180
181 NSS_IMPLEMENT PRBool
182 nssCKObject_IsAttributeTrue(
183 CK_OBJECT_HANDLE object,
184 CK_ATTRIBUTE_TYPE attribute,
185 nssSession *session,
186 NSSSlot *slot,
187 PRStatus *rvStatus)
188 {
189 CK_BBOOL bool;
190 CK_ATTRIBUTE_PTR attr;
191 CK_ATTRIBUTE atemplate = { 0, NULL, 0 };
192 CK_RV ckrv;
193 void *epv = nssSlot_GetCryptokiEPV(slot);
194 attr = &atemplate;
195 NSS_CK_SET_ATTRIBUTE_VAR(attr, attribute, bool);
196 nssSession_EnterMonitor(session);
197 ckrv = CKAPI(epv)->C_GetAttributeValue(session->handle, object,
198 &atemplate, 1);
199 nssSession_ExitMonitor(session);
200 if (ckrv != CKR_OK) {
201 *rvStatus = PR_FAILURE;
202 return PR_FALSE;
203 }
204 *rvStatus = PR_SUCCESS;
205 return (PRBool)(bool == CK_TRUE);
206 }
207
208 NSS_IMPLEMENT PRStatus
209 nssCKObject_SetAttributes(
210 CK_OBJECT_HANDLE object,
211 CK_ATTRIBUTE_PTR obj_template,
212 CK_ULONG count,
213 nssSession *session,
214 NSSSlot *slot)
215 {
216 CK_RV ckrv;
217 void *epv = nssSlot_GetCryptokiEPV(slot);
218 nssSession_EnterMonitor(session);
219 ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, object,
220 obj_template, count);
221 nssSession_ExitMonitor(session);
222 if (ckrv == CKR_OK) {
223 return PR_SUCCESS;
224 } else {
225 return PR_FAILURE;
226 }
227 }
228
229 NSS_IMPLEMENT PRBool
230 nssCKObject_IsTokenObjectTemplate(
231 CK_ATTRIBUTE_PTR objectTemplate,
232 CK_ULONG otsize)
233 {
234 CK_ULONG ul;
235 for (ul = 0; ul < otsize; ul++) {
236 if (objectTemplate[ul].type == CKA_TOKEN) {
237 return (*((CK_BBOOL *)objectTemplate[ul].pValue) == CK_TRUE);
238 }
239 }
240 return PR_FALSE;
241 }
242
243 static NSSCertificateType
244 nss_cert_type_from_ck_attrib(CK_ATTRIBUTE_PTR attrib)
245 {
246 CK_CERTIFICATE_TYPE ckCertType;
247 if (!attrib->pValue) {
248 /* default to PKIX */
249 return NSSCertificateType_PKIX;
250 }
251 ckCertType = *((CK_ULONG *)attrib->pValue);
252 switch (ckCertType) {
253 case CKC_X_509:
254 return NSSCertificateType_PKIX;
255 default:
256 break;
257 }
258 return NSSCertificateType_Unknown;
259 }
260
261 /* incoming pointers must be valid */
262 NSS_IMPLEMENT PRStatus
263 nssCryptokiCertificate_GetAttributes(
264 nssCryptokiObject *certObject,
265 nssSession *sessionOpt,
266 NSSArena *arenaOpt,
267 NSSCertificateType *certTypeOpt,
268 NSSItem *idOpt,
269 NSSDER *encodingOpt,
270 NSSDER *issuerOpt,
271 NSSDER *serialOpt,
272 NSSDER *subjectOpt)
273 {
274 PRStatus status;
275 PRUint32 i;
276 nssSession *session;
277 NSSSlot *slot;
278 CK_ULONG template_size;
279 CK_ATTRIBUTE_PTR attr;
280 CK_ATTRIBUTE cert_template[6];
281 /* Set up a template of all options chosen by caller */
282 NSS_CK_TEMPLATE_START(cert_template, attr, template_size);
283 if (certTypeOpt) {
284 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CERTIFICATE_TYPE);
285 }
286 if (idOpt) {
287 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ID);
288 }
289 if (encodingOpt) {
290 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
291 }
292 if (issuerOpt) {
293 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ISSUER);
294 }
295 if (serialOpt) {
296 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SERIAL_NUMBER);
297 }
298 if (subjectOpt) {
299 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT);
300 }
301 NSS_CK_TEMPLATE_FINISH(cert_template, attr, template_size);
302 if (template_size == 0) {
303 /* caller didn't want anything */
304 return PR_SUCCESS;
305 }
306
307 status = nssToken_GetCachedObjectAttributes(certObject->token, arenaOpt,
308 certObject, CKO_CERTIFICATE,
309 cert_template, template_size);
310 if (status != PR_SUCCESS) {
311
312 session = sessionOpt ? sessionOpt
313 : nssToken_GetDefaultSession(certObject->token);
314 if (!session) {
315 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
316 return PR_FAILURE;
317 }
318
319 slot = nssToken_GetSlot(certObject->token);
320 status = nssCKObject_GetAttributes(certObject->handle,
321 cert_template, template_size,
322 arenaOpt, session, slot);
323 nssSlot_Destroy(slot);
324 if (status != PR_SUCCESS) {
325 return status;
326 }
327 }
328
329 i = 0;
330 if (certTypeOpt) {
331 *certTypeOpt = nss_cert_type_from_ck_attrib(&cert_template[i]);
332 i++;
333 }
334 if (idOpt) {
335 NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], idOpt);
336 i++;
337 }
338 if (encodingOpt) {
339 NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], encodingOpt);
340 i++;
341 }
342 if (issuerOpt) {
343 NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], issuerOpt);
344 i++;
345 }
346 if (serialOpt) {
347 NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], serialOpt);
348 i++;
349 }
350 if (subjectOpt) {
351 NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], subjectOpt);
352 i++;
353 }
354 return PR_SUCCESS;
355 }
356
357 static nssTrustLevel
358 get_nss_trust(
359 CK_TRUST ckt)
360 {
361 nssTrustLevel t;
362 switch (ckt) {
363 case CKT_NSS_NOT_TRUSTED:
364 t = nssTrustLevel_NotTrusted;
365 break;
366 case CKT_NSS_TRUSTED_DELEGATOR:
367 t = nssTrustLevel_TrustedDelegator;
368 break;
369 case CKT_NSS_VALID_DELEGATOR:
370 t = nssTrustLevel_ValidDelegator;
371 break;
372 case CKT_NSS_TRUSTED:
373 t = nssTrustLevel_Trusted;
374 break;
375 case CKT_NSS_MUST_VERIFY_TRUST:
376 t = nssTrustLevel_MustVerify;
377 break;
378 case CKT_NSS_TRUST_UNKNOWN:
379 default:
380 t = nssTrustLevel_Unknown;
381 break;
382 }
383 return t;
384 }
385
386 NSS_IMPLEMENT PRStatus
387 nssCryptokiTrust_GetAttributes(
388 nssCryptokiObject *trustObject,
389 nssSession *sessionOpt,
390 NSSItem *sha1_hash,
391 nssTrustLevel *serverAuth,
392 nssTrustLevel *clientAuth,
393 nssTrustLevel *codeSigning,
394 nssTrustLevel *emailProtection,
395 PRBool *stepUpApproved)
396 {
397 PRStatus status;
398 NSSSlot *slot;
399 nssSession *session;
400 CK_BBOOL isToken = PR_FALSE;
401 CK_BBOOL stepUp = PR_FALSE;
402 CK_TRUST saTrust = CKT_NSS_TRUST_UNKNOWN;
403 CK_TRUST caTrust = CKT_NSS_TRUST_UNKNOWN;
404 CK_TRUST epTrust = CKT_NSS_TRUST_UNKNOWN;
405 CK_TRUST csTrust = CKT_NSS_TRUST_UNKNOWN;
406 CK_ATTRIBUTE_PTR attr;
407 CK_ATTRIBUTE trust_template[7];
408 CK_ATTRIBUTE_PTR sha1_hash_attr;
409 CK_ULONG trust_size;
410
411 /* Use the trust object to find the trust settings */
412 NSS_CK_TEMPLATE_START(trust_template, attr, trust_size);
413 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TOKEN, isToken);
414 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, saTrust);
415 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, caTrust);
416 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, epTrust);
417 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, csTrust);
418 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_STEP_UP_APPROVED, stepUp);
419 sha1_hash_attr = attr;
420 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, sha1_hash);
421 NSS_CK_TEMPLATE_FINISH(trust_template, attr, trust_size);
422
423 status = nssToken_GetCachedObjectAttributes(trustObject->token, NULL,
424 trustObject,
425 CKO_NSS_TRUST,
426 trust_template, trust_size);
427 if (status != PR_SUCCESS) {
428 session = sessionOpt ? sessionOpt
429 : nssToken_GetDefaultSession(trustObject->token);
430 if (!session) {
431 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
432 return PR_FAILURE;
433 }
434
435 slot = nssToken_GetSlot(trustObject->token);
436 status = nssCKObject_GetAttributes(trustObject->handle,
437 trust_template, trust_size,
438 NULL, session, slot);
439 nssSlot_Destroy(slot);
440 if (status != PR_SUCCESS) {
441 return status;
442 }
443 }
444
445 if (sha1_hash_attr->ulValueLen == -1) {
446 /* The trust object does not have the CKA_CERT_SHA1_HASH attribute. */
447 sha1_hash_attr->ulValueLen = 0;
448 }
449 sha1_hash->size = sha1_hash_attr->ulValueLen;
450 *serverAuth = get_nss_trust(saTrust);
451 *clientAuth = get_nss_trust(caTrust);
452 *emailProtection = get_nss_trust(epTrust);
453 *codeSigning = get_nss_trust(csTrust);
454 *stepUpApproved = stepUp;
455 return PR_SUCCESS;
456 }
457
458 NSS_IMPLEMENT PRStatus
459 nssCryptokiCRL_GetAttributes(
460 nssCryptokiObject *crlObject,
461 nssSession *sessionOpt,
462 NSSArena *arenaOpt,
463 NSSItem *encodingOpt,
464 NSSItem *subjectOpt,
465 CK_ULONG *crl_class,
466 NSSUTF8 **urlOpt,
467 PRBool *isKRLOpt)
468 {
469 PRStatus status;
470 NSSSlot *slot;
471 nssSession *session;
472 CK_ATTRIBUTE_PTR attr;
473 CK_ATTRIBUTE crl_template[7];
474 CK_ULONG crl_size;
475 PRUint32 i;
476
477 NSS_CK_TEMPLATE_START(crl_template, attr, crl_size);
478 if (crl_class) {
479 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CLASS);
480 }
481 if (encodingOpt) {
482 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
483 }
484 if (urlOpt) {
485 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_URL);
486 }
487 if (isKRLOpt) {
488 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_KRL);
489 }
490 if (subjectOpt) {
491 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT);
492 }
493 NSS_CK_TEMPLATE_FINISH(crl_template, attr, crl_size);
494
495 status = nssToken_GetCachedObjectAttributes(crlObject->token, NULL,
496 crlObject,
497 CKO_NSS_CRL,
498 crl_template, crl_size);
499 if (status != PR_SUCCESS) {
500 session = sessionOpt ? sessionOpt
501 : nssToken_GetDefaultSession(crlObject->token);
502 if (session == NULL) {
503 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
504 return PR_FAILURE;
505 }
506
507 slot = nssToken_GetSlot(crlObject->token);
508 status = nssCKObject_GetAttributes(crlObject->handle,
509 crl_template, crl_size,
510 arenaOpt, session, slot);
511 nssSlot_Destroy(slot);
512 if (status != PR_SUCCESS) {
513 return status;
514 }
515 }
516
517 i = 0;
518 if (crl_class) {
519 NSS_CK_ATTRIBUTE_TO_ULONG(&crl_template[i], *crl_class);
520 i++;
521 }
522 if (encodingOpt) {
523 NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], encodingOpt);
524 i++;
525 }
526 if (urlOpt) {
527 NSS_CK_ATTRIBUTE_TO_UTF8(&crl_template[i], *urlOpt);
528 i++;
529 }
530 if (isKRLOpt) {
531 NSS_CK_ATTRIBUTE_TO_BOOL(&crl_template[i], *isKRLOpt);
532 i++;
533 }
534 if (subjectOpt) {
535 NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], subjectOpt);
536 i++;
537 }
538 return PR_SUCCESS;
539 }
540
541 NSS_IMPLEMENT PRStatus
542 nssCryptokiPrivateKey_SetCertificate(
543 nssCryptokiObject *keyObject,
544 nssSession *sessionOpt,
545 const NSSUTF8 *nickname,
546 NSSItem *id,
547 NSSDER *subject)
548 {
549 CK_RV ckrv;
550 CK_ATTRIBUTE_PTR attr;
551 CK_ATTRIBUTE key_template[3];
552 CK_ULONG key_size;
553 void *epv = nssToken_GetCryptokiEPV(keyObject->token);
554 nssSession *session;
555 NSSToken *token = keyObject->token;
556 nssSession *defaultSession = nssToken_GetDefaultSession(token);
557 PRBool createdSession = PR_FALSE;
558
559 NSS_CK_TEMPLATE_START(key_template, attr, key_size);
560 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
561 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
562 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
563 NSS_CK_TEMPLATE_FINISH(key_template, attr, key_size);
564
565 if (sessionOpt) {
566 if (!nssSession_IsReadWrite(sessionOpt)) {
567 return PR_FAILURE;
568 }
569 session = sessionOpt;
570 } else if (defaultSession && nssSession_IsReadWrite(defaultSession)) {
571 session = defaultSession;
572 } else {
573 NSSSlot *slot = nssToken_GetSlot(token);
574 session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
575 nssSlot_Destroy(slot);
576 if (!session) {
577 return PR_FAILURE;
578 }
579 createdSession = PR_TRUE;
580 }
581
582 ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle,
583 keyObject->handle,
584 key_template,
585 key_size);
586
587 if (createdSession) {
588 nssSession_Destroy(session);
589 }
590
591 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
592 }
OLDNEW
« no previous file with comments | « nss/lib/dev/ckhelper.h ('k') | nss/lib/dev/dev.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698