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

Side by Side Diff: nss/lib/softoken/lowkey.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/softoken/lgglue.c ('k') | nss/lib/softoken/lowkeyi.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 #include "lowkeyi.h"
5 #include "secoid.h"
6 #include "secitem.h"
7 #include "secder.h"
8 #include "base64.h"
9 #include "secasn1.h"
10 #include "secerr.h"
11
12 #ifndef NSS_DISABLE_ECC
13 #include "softoken.h"
14 #endif
15
16 SEC_ASN1_MKSUB(SEC_AnyTemplate)
17 SEC_ASN1_MKSUB(SEC_BitStringTemplate)
18 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
19 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
20
21 const SEC_ASN1Template nsslowkey_AttributeTemplate[] = {
22 { SEC_ASN1_SEQUENCE,
23 0, NULL, sizeof(NSSLOWKEYAttribute) },
24 { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) },
25 { SEC_ASN1_SET_OF | SEC_ASN1_XTRN ,
26 offsetof(NSSLOWKEYAttribute, attrValue),
27 SEC_ASN1_SUB(SEC_AnyTemplate) },
28 { 0 }
29 };
30
31 const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = {
32 { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate },
33 };
34 /* ASN1 Templates for new decoder/encoder */
35 const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = {
36 { SEC_ASN1_SEQUENCE,
37 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) },
38 { SEC_ASN1_INTEGER,
39 offsetof(NSSLOWKEYPrivateKeyInfo,version) },
40 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
41 offsetof(NSSLOWKEYPrivateKeyInfo,algorithm),
42 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
43 { SEC_ASN1_OCTET_STRING,
44 offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) },
45 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
46 offsetof(NSSLOWKEYPrivateKeyInfo, attributes),
47 nsslowkey_SetOfAttributeTemplate },
48 { 0 }
49 };
50
51 const SEC_ASN1Template nsslowkey_PQGParamsTemplate[] = {
52 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) },
53 { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) },
54 { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) },
55 { SEC_ASN1_INTEGER, offsetof(PQGParams,base) },
56 { 0 }
57 };
58
59 const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[] = {
60 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
61 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.version) },
62 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.modulus) },
63 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.publicExponent) },
64 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.privateExponent) },
65 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime1) },
66 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime2) },
67 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent1) },
68 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent2) },
69 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.coefficient) },
70 { 0 }
71 };
72
73
74 const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = {
75 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
76 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.publicValue) },
77 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) },
78 { 0 }
79 };
80
81 const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[] = {
82 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) },
83 };
84
85 const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[] = {
86 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
87 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.publicValue) },
88 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.privateValue) },
89 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.base) },
90 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.prime) },
91 { 0 }
92 };
93
94 #ifndef NSS_DISABLE_ECC
95
96 /* XXX This is just a placeholder for later when we support
97 * generic curves and need full-blown support for parsing EC
98 * parameters. For now, we only support named curves in which
99 * EC params are simply encoded as an object ID and we don't
100 * use nsslowkey_ECParamsTemplate.
101 */
102 const SEC_ASN1Template nsslowkey_ECParamsTemplate[] = {
103 { SEC_ASN1_CHOICE, offsetof(ECParams,type), NULL, sizeof(ECParams) },
104 { SEC_ASN1_OBJECT_ID, offsetof(ECParams,curveOID), NULL, ec_params_named },
105 { 0 }
106 };
107
108
109 /* NOTE: The SECG specification allows the private key structure
110 * to contain curve parameters but recommends that they be stored
111 * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo
112 * instead.
113 */
114 const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[] = {
115 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
116 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.ec.version) },
117 { SEC_ASN1_OCTET_STRING,
118 offsetof(NSSLOWKEYPrivateKey,u.ec.privateValue) },
119 /* XXX The following template works for now since we only
120 * support named curves for which the parameters are
121 * encoded as an object ID. When we support generic curves,
122 * we'll need to define nsslowkey_ECParamsTemplate
123 */
124 #if 1
125 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
126 SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
127 SEC_ASN1_XTRN | 0,
128 offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams.curveOID),
129 SEC_ASN1_SUB(SEC_ObjectIDTemplate) },
130 #else
131 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
132 SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0,
133 offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams),
134 nsslowkey_ECParamsTemplate },
135 #endif
136 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
137 SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
138 SEC_ASN1_XTRN | 1,
139 offsetof(NSSLOWKEYPrivateKey,u.ec.publicValue),
140 SEC_ASN1_SUB(SEC_BitStringTemplate) },
141 { 0 }
142 };
143 #endif /* NSS_DISABLE_ECC */
144 /*
145 * See bugzilla bug 125359
146 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
147 * all of the templates above that en/decode into integers must be converted
148 * from ASN.1's signed integer type. This is done by marking either the
149 * source or destination (encoding or decoding, respectively) type as
150 * siUnsignedInteger.
151 */
152
153 void
154 prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
155 {
156 key->u.rsa.modulus.type = siUnsignedInteger;
157 key->u.rsa.publicExponent.type = siUnsignedInteger;
158 key->u.rsa.privateExponent.type = siUnsignedInteger;
159 key->u.rsa.prime1.type = siUnsignedInteger;
160 key->u.rsa.prime2.type = siUnsignedInteger;
161 key->u.rsa.exponent1.type = siUnsignedInteger;
162 key->u.rsa.exponent2.type = siUnsignedInteger;
163 key->u.rsa.coefficient.type = siUnsignedInteger;
164 }
165
166 void
167 prepare_low_pqg_params_for_asn1(PQGParams *params)
168 {
169 params->prime.type = siUnsignedInteger;
170 params->subPrime.type = siUnsignedInteger;
171 params->base.type = siUnsignedInteger;
172 }
173
174 void
175 prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
176 {
177 key->u.dsa.publicValue.type = siUnsignedInteger;
178 key->u.dsa.privateValue.type = siUnsignedInteger;
179 key->u.dsa.params.prime.type = siUnsignedInteger;
180 key->u.dsa.params.subPrime.type = siUnsignedInteger;
181 key->u.dsa.params.base.type = siUnsignedInteger;
182 }
183
184 void
185 prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key)
186 {
187 key->u.dsa.privateValue.type = siUnsignedInteger;
188 }
189
190 void
191 prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
192 {
193 key->u.dh.prime.type = siUnsignedInteger;
194 key->u.dh.base.type = siUnsignedInteger;
195 key->u.dh.publicValue.type = siUnsignedInteger;
196 key->u.dh.privateValue.type = siUnsignedInteger;
197 }
198
199 #ifndef NSS_DISABLE_ECC
200 void
201 prepare_low_ecparams_for_asn1(ECParams *params)
202 {
203 params->DEREncoding.type = siUnsignedInteger;
204 params->curveOID.type = siUnsignedInteger;
205 }
206
207 void
208 prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key)
209 {
210 key->u.ec.version.type = siUnsignedInteger;
211 key->u.ec.ecParams.DEREncoding.type = siUnsignedInteger;
212 key->u.ec.ecParams.curveOID.type = siUnsignedInteger;
213 key->u.ec.privateValue.type = siUnsignedInteger;
214 key->u.ec.publicValue.type = siUnsignedInteger;
215 }
216 #endif /* NSS_DISABLE_ECC */
217
218 void
219 nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *privk)
220 {
221 if (privk && privk->arena) {
222 PORT_FreeArena(privk->arena, PR_TRUE);
223 }
224 }
225
226 void
227 nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *pubk)
228 {
229 if (pubk && pubk->arena) {
230 PORT_FreeArena(pubk->arena, PR_FALSE);
231 }
232 }
233 unsigned
234 nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubk)
235 {
236 unsigned char b0;
237
238 /* interpret modulus length as key strength... in
239 * fortezza that's the public key length */
240
241 switch (pubk->keyType) {
242 case NSSLOWKEYRSAKey:
243 b0 = pubk->u.rsa.modulus.data[0];
244 return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
245 default:
246 break;
247 }
248 return 0;
249 }
250
251 unsigned
252 nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privk)
253 {
254
255 unsigned char b0;
256
257 switch (privk->keyType) {
258 case NSSLOWKEYRSAKey:
259 b0 = privk->u.rsa.modulus.data[0];
260 return b0 ? privk->u.rsa.modulus.len : privk->u.rsa.modulus.len - 1;
261 default:
262 break;
263 }
264 return 0;
265 }
266
267 NSSLOWKEYPublicKey *
268 nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk)
269 {
270 NSSLOWKEYPublicKey *pubk;
271 PLArenaPool *arena;
272
273
274 arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
275 if (arena == NULL) {
276 PORT_SetError (SEC_ERROR_NO_MEMORY);
277 return NULL;
278 }
279
280 switch(privk->keyType) {
281 case NSSLOWKEYRSAKey:
282 case NSSLOWKEYNullKey:
283 pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
284 sizeof (NSSLOWKEYPublicKey));
285 if (pubk != NULL) {
286 SECStatus rv;
287
288 pubk->arena = arena;
289 pubk->keyType = privk->keyType;
290 if (privk->keyType == NSSLOWKEYNullKey) return pubk;
291 rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus,
292 &privk->u.rsa.modulus);
293 if (rv == SECSuccess) {
294 rv = SECITEM_CopyItem (arena, &pubk->u.rsa.publicExponent,
295 &privk->u.rsa.publicExponent);
296 if (rv == SECSuccess)
297 return pubk;
298 }
299 } else {
300 PORT_SetError (SEC_ERROR_NO_MEMORY);
301 }
302 break;
303 case NSSLOWKEYDSAKey:
304 pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
305 sizeof(NSSLOWKEYPublicKey));
306 if (pubk != NULL) {
307 SECStatus rv;
308
309 pubk->arena = arena;
310 pubk->keyType = privk->keyType;
311 rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue,
312 &privk->u.dsa.publicValue);
313 if (rv != SECSuccess) break;
314 rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime,
315 &privk->u.dsa.params.prime);
316 if (rv != SECSuccess) break;
317 rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime,
318 &privk->u.dsa.params.subPrime);
319 if (rv != SECSuccess) break;
320 rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base,
321 &privk->u.dsa.params.base);
322 if (rv == SECSuccess) return pubk;
323 }
324 break;
325 case NSSLOWKEYDHKey:
326 pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
327 sizeof(NSSLOWKEYPublicKey));
328 if (pubk != NULL) {
329 SECStatus rv;
330
331 pubk->arena = arena;
332 pubk->keyType = privk->keyType;
333 rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue,
334 &privk->u.dh.publicValue);
335 if (rv != SECSuccess) break;
336 rv = SECITEM_CopyItem(arena, &pubk->u.dh.prime,
337 &privk->u.dh.prime);
338 if (rv != SECSuccess) break;
339 rv = SECITEM_CopyItem(arena, &pubk->u.dh.base,
340 &privk->u.dh.base);
341 if (rv == SECSuccess) return pubk;
342 }
343 break;
344 #ifndef NSS_DISABLE_ECC
345 case NSSLOWKEYECKey:
346 pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
347 sizeof(NSSLOWKEYPublicKey));
348 if (pubk != NULL) {
349 SECStatus rv;
350
351 pubk->arena = arena;
352 pubk->keyType = privk->keyType;
353 rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue,
354 &privk->u.ec.publicValue);
355 if (rv != SECSuccess) break;
356 pubk->u.ec.ecParams.arena = arena;
357 /* Copy the rest of the params */
358 rv = EC_CopyParams(arena, &(pubk->u.ec.ecParams),
359 &(privk->u.ec.ecParams));
360 if (rv == SECSuccess) return pubk;
361 }
362 break;
363 #endif /* NSS_DISABLE_ECC */
364 /* No Fortezza in Low Key implementations (Fortezza keys aren't
365 * stored in our data base */
366 default:
367 break;
368 }
369
370 PORT_FreeArena (arena, PR_FALSE);
371 return NULL;
372 }
373
374 NSSLOWKEYPrivateKey *
375 nsslowkey_CopyPrivateKey(NSSLOWKEYPrivateKey *privKey)
376 {
377 NSSLOWKEYPrivateKey *returnKey = NULL;
378 SECStatus rv = SECFailure;
379 PLArenaPool *poolp;
380
381 if(!privKey) {
382 return NULL;
383 }
384
385 poolp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
386 if(!poolp) {
387 return NULL;
388 }
389
390 returnKey = (NSSLOWKEYPrivateKey*)PORT_ArenaZAlloc(poolp, sizeof(NSSLOWKEYPr ivateKey));
391 if(!returnKey) {
392 rv = SECFailure;
393 goto loser;
394 }
395
396 returnKey->keyType = privKey->keyType;
397 returnKey->arena = poolp;
398
399 switch(privKey->keyType) {
400 case NSSLOWKEYRSAKey:
401 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.modulus),
402 &(privKey->u.rsa.modulus));
403 if(rv != SECSuccess) break;
404 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.version),
405 &(privKey->u.rsa.version));
406 if(rv != SECSuccess) break;
407 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.publicExponent),
408 &(privKey->u.rsa.publicExponent));
409 if(rv != SECSuccess) break;
410 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.privateExponent),
411 &(privKey->u.rsa.privateExponent));
412 if(rv != SECSuccess) break;
413 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime1),
414 &(privKey->u.rsa.prime1));
415 if(rv != SECSuccess) break;
416 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime2),
417 &(privKey->u.rsa.prime2));
418 if(rv != SECSuccess) break;
419 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent1),
420 &(privKey->u.rsa.exponent1));
421 if(rv != SECSuccess) break;
422 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent2),
423 &(privKey->u.rsa.exponent2));
424 if(rv != SECSuccess) break;
425 rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.coefficient),
426 &(privKey->u.rsa.coefficient));
427 if(rv != SECSuccess) break;
428 break;
429 case NSSLOWKEYDSAKey:
430 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.publicValue),
431 &(privKey->u.dsa.publicValue));
432 if(rv != SECSuccess) break;
433 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.privateValue),
434 &(privKey->u.dsa.privateValue));
435 if(rv != SECSuccess) break;
436 returnKey->u.dsa.params.arena = poolp;
437 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.prime),
438 &(privKey->u.dsa.params.prime));
439 if(rv != SECSuccess) break;
440 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.subPrime),
441 &(privKey->u.dsa.params.subPrime));
442 if(rv != SECSuccess) break;
443 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.base),
444 &(privKey->u.dsa.params.base));
445 if(rv != SECSuccess) break;
446 break;
447 case NSSLOWKEYDHKey:
448 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.publicValue),
449 &(privKey->u.dh.publicValue));
450 if(rv != SECSuccess) break;
451 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.privateValue),
452 &(privKey->u.dh.privateValue));
453 if(rv != SECSuccess) break;
454 returnKey->u.dsa.params.arena = poolp;
455 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.prime),
456 &(privKey->u.dh.prime));
457 if(rv != SECSuccess) break;
458 rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.base),
459 &(privKey->u.dh.base));
460 if(rv != SECSuccess) break;
461 break;
462 #ifndef NSS_DISABLE_ECC
463 case NSSLOWKEYECKey:
464 rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.version),
465 &(privKey->u.ec.version));
466 if(rv != SECSuccess) break;
467 rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.publicValue),
468 &(privKey->u.ec.publicValue));
469 if(rv != SECSuccess) break;
470 rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.privateValue),
471 &(privKey->u.ec.privateValue));
472 if(rv != SECSuccess) break;
473 returnKey->u.ec.ecParams.arena = poolp;
474 /* Copy the rest of the params */
475 rv = EC_CopyParams(poolp, &(returnKey->u.ec.ecParams),
476 &(privKey->u.ec.ecParams));
477 if (rv != SECSuccess) break;
478 break;
479 #endif /* NSS_DISABLE_ECC */
480 default:
481 rv = SECFailure;
482 }
483
484 loser:
485
486 if(rv != SECSuccess) {
487 PORT_FreeArena(poolp, PR_TRUE);
488 returnKey = NULL;
489 }
490
491 return returnKey;
492 }
OLDNEW
« no previous file with comments | « nss/lib/softoken/lgglue.c ('k') | nss/lib/softoken/lowkeyi.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698