comparison nss/lib/pkcs7/p7create.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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 /*
6 * PKCS7 creation.
7 */
8
9 #include "p7local.h"
10
11 #include "cert.h"
12 #include "secasn1.h"
13 #include "secitem.h"
14 #include "secoid.h"
15 #include "pk11func.h"
16 #include "prtime.h"
17 #include "secerr.h"
18 #include "secder.h"
19 #include "secpkcs5.h"
20
21 const int NSS_PBE_DEFAULT_ITERATION_COUNT = 2000; /* used in p12e.c too */
22
23 static SECStatus
24 sec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PLArenaPool *poolp,
25 SECOidTag kind, PRBool detached)
26 {
27 void *thing;
28 int version;
29 SECItem *versionp;
30 SECStatus rv;
31
32 PORT_Assert (cinfo != NULL && poolp != NULL);
33 if (cinfo == NULL || poolp == NULL)
34 return SECFailure;
35
36 cinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
37 PORT_Assert (cinfo->contentTypeTag
38 && cinfo->contentTypeTag->offset == kind);
39
40 rv = SECITEM_CopyItem (poolp, &(cinfo->contentType),
41 &(cinfo->contentTypeTag->oid));
42 if (rv != SECSuccess)
43 return rv;
44
45 if (detached)
46 return SECSuccess;
47
48 switch (kind) {
49 default:
50 case SEC_OID_PKCS7_DATA:
51 thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem));
52 cinfo->content.data = (SECItem*)thing;
53 versionp = NULL;
54 version = -1;
55 break;
56 case SEC_OID_PKCS7_DIGESTED_DATA:
57 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData));
58 cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing;
59 versionp = &(cinfo->content.digestedData->version);
60 version = SEC_PKCS7_DIGESTED_DATA_VERSION;
61 break;
62 case SEC_OID_PKCS7_ENCRYPTED_DATA:
63 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData));
64 cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing;
65 versionp = &(cinfo->content.encryptedData->version);
66 version = SEC_PKCS7_ENCRYPTED_DATA_VERSION;
67 break;
68 case SEC_OID_PKCS7_ENVELOPED_DATA:
69 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData));
70 cinfo->content.envelopedData =
71 (SEC_PKCS7EnvelopedData*)thing;
72 versionp = &(cinfo->content.envelopedData->version);
73 version = SEC_PKCS7_ENVELOPED_DATA_VERSION;
74 break;
75 case SEC_OID_PKCS7_SIGNED_DATA:
76 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData));
77 cinfo->content.signedData =
78 (SEC_PKCS7SignedData*)thing;
79 versionp = &(cinfo->content.signedData->version);
80 version = SEC_PKCS7_SIGNED_DATA_VERSION;
81 break;
82 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
83 thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData));
84 cinfo->content.signedAndEnvelopedData =
85 (SEC_PKCS7SignedAndEnvelopedData*)thing;
86 versionp = &(cinfo->content.signedAndEnvelopedData->version);
87 version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION;
88 break;
89 }
90
91 if (thing == NULL)
92 return SECFailure;
93
94 if (versionp != NULL) {
95 SECItem *dummy;
96
97 PORT_Assert (version >= 0);
98 dummy = SEC_ASN1EncodeInteger (poolp, versionp, version);
99 if (dummy == NULL)
100 return SECFailure;
101 PORT_Assert (dummy == versionp);
102 }
103
104 return SECSuccess;
105 }
106
107
108 static SEC_PKCS7ContentInfo *
109 sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached,
110 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
111 {
112 SEC_PKCS7ContentInfo *cinfo;
113 PLArenaPool *poolp;
114 SECStatus rv;
115
116 poolp = PORT_NewArena (1024); /* XXX what is right value? */
117 if (poolp == NULL)
118 return NULL;
119
120 cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
121 if (cinfo == NULL) {
122 PORT_FreeArena (poolp, PR_FALSE);
123 return NULL;
124 }
125
126 cinfo->poolp = poolp;
127 cinfo->pwfn = pwfn;
128 cinfo->pwfn_arg = pwfn_arg;
129 cinfo->created = PR_TRUE;
130 cinfo->refCount = 1;
131
132 rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached);
133 if (rv != SECSuccess) {
134 PORT_FreeArena (poolp, PR_FALSE);
135 return NULL;
136 }
137
138 return cinfo;
139 }
140
141
142 /*
143 * Add a signer to a PKCS7 thing, verifying the signature cert first.
144 * Any error returns SECFailure.
145 *
146 * XXX Right now this only adds the *first* signer. It fails if you try
147 * to add a second one -- this needs to be fixed.
148 */
149 static SECStatus
150 sec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo,
151 CERTCertificate * cert,
152 SECCertUsage certusage,
153 CERTCertDBHandle * certdb,
154 SECOidTag digestalgtag,
155 SECItem * digestdata)
156 {
157 SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp;
158 SECAlgorithmID *digestalg, **digestalgs, ***digestalgsp;
159 SECItem *digest, **digests, ***digestsp;
160 SECItem * dummy;
161 void * mark;
162 SECStatus rv;
163 SECOidTag kind;
164
165 kind = SEC_PKCS7ContentType (cinfo);
166 switch (kind) {
167 case SEC_OID_PKCS7_SIGNED_DATA:
168 {
169 SEC_PKCS7SignedData *sdp;
170
171 sdp = cinfo->content.signedData;
172 digestalgsp = &(sdp->digestAlgorithms);
173 digestsp = &(sdp->digests);
174 signerinfosp = &(sdp->signerInfos);
175 }
176 break;
177 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
178 {
179 SEC_PKCS7SignedAndEnvelopedData *saedp;
180
181 saedp = cinfo->content.signedAndEnvelopedData;
182 digestalgsp = &(saedp->digestAlgorithms);
183 digestsp = &(saedp->digests);
184 signerinfosp = &(saedp->signerInfos);
185 }
186 break;
187 default:
188 return SECFailure; /* XXX set an error? */
189 }
190
191 /*
192 * XXX I think that CERT_VerifyCert should do this if *it* is passed
193 * a NULL database.
194 */
195 if (certdb == NULL) {
196 certdb = CERT_GetDefaultCertDB();
197 if (certdb == NULL)
198 return SECFailure; /* XXX set an error? */
199 }
200
201 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
202 cinfo->pwfn_arg, NULL) != SECSuccess)
203 {
204 /* XXX Did CERT_VerifyCert set an error? */
205 return SECFailure;
206 }
207
208 /*
209 * XXX This is the check that we do not already have a signer.
210 * This is not what we really want -- we want to allow this
211 * and *add* the new signer.
212 */
213 PORT_Assert (*signerinfosp == NULL
214 && *digestalgsp == NULL && *digestsp == NULL);
215 if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL)
216 return SECFailure;
217
218 mark = PORT_ArenaMark (cinfo->poolp);
219
220 signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp,
221 sizeof(SEC_PKCS7SignerInfo));
222 if (signerinfo == NULL) {
223 PORT_ArenaRelease (cinfo->poolp, mark);
224 return SECFailure;
225 }
226
227 dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version,
228 SEC_PKCS7_SIGNER_INFO_VERSION);
229 if (dummy == NULL) {
230 PORT_ArenaRelease (cinfo->poolp, mark);
231 return SECFailure;
232 }
233 PORT_Assert (dummy == &signerinfo->version);
234
235 signerinfo->cert = CERT_DupCertificate (cert);
236 if (signerinfo->cert == NULL) {
237 PORT_ArenaRelease (cinfo->poolp, mark);
238 return SECFailure;
239 }
240
241 signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
242 if (signerinfo->issuerAndSN == NULL) {
243 PORT_ArenaRelease (cinfo->poolp, mark);
244 return SECFailure;
245 }
246
247 rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg,
248 digestalgtag, NULL);
249 if (rv != SECSuccess) {
250 PORT_ArenaRelease (cinfo->poolp, mark);
251 return SECFailure;
252 }
253
254 /*
255 * Okay, now signerinfo is all set. We just need to put it and its
256 * companions (another copy of the digest algorithm, and the digest
257 * itself if given) into the main structure.
258 *
259 * XXX If we are handling more than one signer, the following code
260 * needs to look through the digest algorithms already specified
261 * and see if the same one is there already. If it is, it does not
262 * need to be added again. Also, if it is there *and* the digest
263 * is not null, then the digest given should match the digest already
264 * specified -- if not, that is an error. Finally, the new signerinfo
265 * should be *added* to the set already found.
266 */
267
268 signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp,
269 2 * sizeof(SEC_PKCS7SignerInfo *));
270 if (signerinfos == NULL) {
271 PORT_ArenaRelease (cinfo->poolp, mark);
272 return SECFailure;
273 }
274 signerinfos[0] = signerinfo;
275 signerinfos[1] = NULL;
276
277 digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID));
278 digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *));
279 if (digestalg == NULL || digestalgs == NULL) {
280 PORT_ArenaRelease (cinfo->poolp, mark);
281 return SECFailure;
282 }
283 rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL);
284 if (rv != SECSuccess) {
285 PORT_ArenaRelease (cinfo->poolp, mark);
286 return SECFailure;
287 }
288 digestalgs[0] = digestalg;
289 digestalgs[1] = NULL;
290
291 if (digestdata != NULL) {
292 digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem));
293 digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp,
294 2 * sizeof(SECItem *));
295 if (digest == NULL || digests == NULL) {
296 PORT_ArenaRelease (cinfo->poolp, mark);
297 return SECFailure;
298 }
299 rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata);
300 if (rv != SECSuccess) {
301 PORT_ArenaRelease (cinfo->poolp, mark);
302 return SECFailure;
303 }
304 digests[0] = digest;
305 digests[1] = NULL;
306 } else {
307 digests = NULL;
308 }
309
310 *signerinfosp = signerinfos;
311 *digestalgsp = digestalgs;
312 *digestsp = digests;
313
314 PORT_ArenaUnmark(cinfo->poolp, mark);
315 return SECSuccess;
316 }
317
318
319 /*
320 * Helper function for creating an empty signedData.
321 */
322 static SEC_PKCS7ContentInfo *
323 sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg)
324 {
325 SEC_PKCS7ContentInfo *cinfo;
326 SEC_PKCS7SignedData *sigd;
327 SECStatus rv;
328
329 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE,
330 pwfn, pwfn_arg);
331 if (cinfo == NULL)
332 return NULL;
333
334 sigd = cinfo->content.signedData;
335 PORT_Assert (sigd != NULL);
336
337 /*
338 * XXX Might we want to allow content types other than data?
339 * If so, via what interface?
340 */
341 rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp,
342 SEC_OID_PKCS7_DATA, PR_TRUE);
343 if (rv != SECSuccess) {
344 SEC_PKCS7DestroyContentInfo (cinfo);
345 return NULL;
346 }
347
348 return cinfo;
349 }
350
351
352 /*
353 * Start a PKCS7 signing context.
354 *
355 * "cert" is the cert that will be used to sign the data. It will be
356 * checked for validity.
357 *
358 * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
359 * XXX Maybe SECCertUsage should be split so that our caller just says
360 * "email" and *we* add the "signing" part -- otherwise our caller
361 * could be lying about the usage; we do not want to allow encryption
362 * certs for signing or vice versa.
363 *
364 * "certdb" is the cert database to use for verifying the cert.
365 * It can be NULL if a default database is available (like in the client).
366 *
367 * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
368 *
369 * "digest" is the actual digest of the data. It must be provided in
370 * the case of detached data or NULL if the content will be included.
371 *
372 * The return value can be passed to functions which add things to
373 * it like attributes, then eventually to SEC_PKCS7Encode() or to
374 * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
375 * SEC_PKCS7DestroyContentInfo().
376 *
377 * An error results in a return value of NULL and an error set.
378 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
379 */
380 SEC_PKCS7ContentInfo *
381 SEC_PKCS7CreateSignedData (CERTCertificate *cert,
382 SECCertUsage certusage,
383 CERTCertDBHandle *certdb,
384 SECOidTag digestalg,
385 SECItem *digest,
386 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
387 {
388 SEC_PKCS7ContentInfo *cinfo;
389 SECStatus rv;
390
391 cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg);
392 if (cinfo == NULL)
393 return NULL;
394
395 rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb,
396 digestalg, digest);
397 if (rv != SECSuccess) {
398 SEC_PKCS7DestroyContentInfo (cinfo);
399 return NULL;
400 }
401
402 return cinfo;
403 }
404
405
406 static SEC_PKCS7Attribute *
407 sec_pkcs7_create_attribute (PLArenaPool *poolp, SECOidTag oidtag,
408 SECItem *value, PRBool encoded)
409 {
410 SEC_PKCS7Attribute *attr;
411 SECItem **values;
412 void *mark;
413
414 PORT_Assert (poolp != NULL);
415 mark = PORT_ArenaMark (poolp);
416
417 attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp,
418 sizeof(SEC_PKCS7Attribute));
419 if (attr == NULL)
420 goto loser;
421
422 attr->typeTag = SECOID_FindOIDByTag (oidtag);
423 if (attr->typeTag == NULL)
424 goto loser;
425
426 if (SECITEM_CopyItem (poolp, &(attr->type),
427 &(attr->typeTag->oid)) != SECSuccess)
428 goto loser;
429
430 values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *));
431 if (values == NULL)
432 goto loser;
433
434 if (value != NULL) {
435 SECItem *copy;
436
437 copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
438 if (copy == NULL)
439 goto loser;
440
441 if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess)
442 goto loser;
443
444 value = copy;
445 }
446
447 values[0] = value;
448 values[1] = NULL;
449 attr->values = values;
450 attr->encoded = encoded;
451
452 PORT_ArenaUnmark (poolp, mark);
453 return attr;
454
455 loser:
456 PORT_Assert (mark != NULL);
457 PORT_ArenaRelease (poolp, mark);
458 return NULL;
459 }
460
461
462 static SECStatus
463 sec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo,
464 SEC_PKCS7Attribute ***attrsp,
465 SEC_PKCS7Attribute *attr)
466 {
467 SEC_PKCS7Attribute **attrs;
468 SECItem *ct_value;
469 void *mark;
470
471 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
472 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
473 return SECFailure;
474
475 attrs = *attrsp;
476 if (attrs != NULL) {
477 int count;
478
479 /*
480 * We already have some attributes, and just need to add this
481 * new one.
482 */
483
484 /*
485 * We should already have the *required* attributes, which were
486 * created/added at the same time the first attribute was added.
487 */
488 PORT_Assert (sec_PKCS7FindAttribute (attrs,
489 SEC_OID_PKCS9_CONTENT_TYPE,
490 PR_FALSE) != NULL);
491 PORT_Assert (sec_PKCS7FindAttribute (attrs,
492 SEC_OID_PKCS9_MESSAGE_DIGEST,
493 PR_FALSE) != NULL);
494
495 for (count = 0; attrs[count] != NULL; count++)
496 ;
497 attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs,
498 (count + 1) * sizeof(SEC_PKCS7Attribute *),
499 (count + 2) * sizeof(SEC_PKCS7Attribute *));
500 if (attrs == NULL)
501 return SECFailure;
502
503 attrs[count] = attr;
504 attrs[count+1] = NULL;
505 *attrsp = attrs;
506
507 return SECSuccess;
508 }
509
510 /*
511 * This is the first time an attribute is going in.
512 * We need to create and add the required attributes, and then
513 * we will also add in the one our caller gave us.
514 */
515
516 /*
517 * There are 2 required attributes, plus the one our caller wants
518 * to add, plus we always end with a NULL one. Thus, four slots.
519 */
520 attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp,
521 4 * sizeof(SEC_PKCS7Attribute *));
522 if (attrs == NULL)
523 return SECFailure;
524
525 mark = PORT_ArenaMark (cinfo->poolp);
526
527 /*
528 * First required attribute is the content type of the data
529 * being signed.
530 */
531 ct_value = &(cinfo->content.signedData->contentInfo.contentType);
532 attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp,
533 SEC_OID_PKCS9_CONTENT_TYPE,
534 ct_value, PR_FALSE);
535 /*
536 * Second required attribute is the message digest of the data
537 * being signed; we leave the value NULL for now (just create
538 * the place for it to go), and the encoder will fill it in later.
539 */
540 attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp,
541 SEC_OID_PKCS9_MESSAGE_DIGEST,
542 NULL, PR_FALSE);
543 if (attrs[0] == NULL || attrs[1] == NULL) {
544 PORT_ArenaRelease (cinfo->poolp, mark);
545 return SECFailure;
546 }
547
548 attrs[2] = attr;
549 attrs[3] = NULL;
550 *attrsp = attrs;
551
552 PORT_ArenaUnmark (cinfo->poolp, mark);
553 return SECSuccess;
554 }
555
556
557 /*
558 * Add the signing time to the authenticated (i.e. signed) attributes
559 * of "cinfo". This is expected to be included in outgoing signed
560 * messages for email (S/MIME) but is likely useful in other situations.
561 *
562 * This should only be added once; a second call will either do
563 * nothing or replace an old signing time with a newer one.
564 *
565 * XXX This will probably just shove the current time into "cinfo"
566 * but it will not actually get signed until the entire item is
567 * processed for encoding. Is this (expected to be small) delay okay?
568 *
569 * "cinfo" should be of type signedData (the only kind of pkcs7 data
570 * that is allowed authenticated attributes); SECFailure will be returned
571 * if it is not.
572 */
573 SECStatus
574 SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo)
575 {
576 SEC_PKCS7SignerInfo **signerinfos;
577 SEC_PKCS7Attribute *attr;
578 SECItem stime;
579 SECStatus rv;
580 int si;
581
582 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
583 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
584 return SECFailure;
585
586 signerinfos = cinfo->content.signedData->signerInfos;
587
588 /* There has to be a signer, or it makes no sense. */
589 if (signerinfos == NULL || signerinfos[0] == NULL)
590 return SECFailure;
591
592 rv = DER_EncodeTimeChoice(NULL, &stime, PR_Now());
593 if (rv != SECSuccess)
594 return rv;
595
596 attr = sec_pkcs7_create_attribute (cinfo->poolp,
597 SEC_OID_PKCS9_SIGNING_TIME,
598 &stime, PR_FALSE);
599 SECITEM_FreeItem (&stime, PR_FALSE);
600
601 if (attr == NULL)
602 return SECFailure;
603
604 rv = SECSuccess;
605 for (si = 0; signerinfos[si] != NULL; si++) {
606 SEC_PKCS7Attribute *oattr;
607
608 oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr,
609 SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE);
610 PORT_Assert (oattr == NULL);
611 if (oattr != NULL)
612 continue; /* XXX or would it be better to replace it? */
613
614 rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr),
615 attr);
616 if (rv != SECSuccess)
617 break; /* could try to continue, but may as well give up now */
618 }
619
620 return rv;
621 }
622
623
624 /*
625 * Add the specified attribute to the authenticated (i.e. signed) attributes
626 * of "cinfo" -- "oidtag" describes the attribute and "value" is the
627 * value to be associated with it. NOTE! "value" must already be encoded;
628 * no interpretation of "oidtag" is done. Also, it is assumed that this
629 * signedData has only one signer -- if we ever need to add attributes
630 * when there is more than one signature, we need a way to specify *which*
631 * signature should get the attribute.
632 *
633 * XXX Technically, a signed attribute can have multiple values; if/when
634 * we ever need to support an attribute which takes multiple values, we
635 * either need to change this interface or create an AddSignedAttributeValue
636 * which can be called subsequently, and would then append a value.
637 *
638 * "cinfo" should be of type signedData (the only kind of pkcs7 data
639 * that is allowed authenticated attributes); SECFailure will be returned
640 * if it is not.
641 */
642 SECStatus
643 SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
644 SECOidTag oidtag,
645 SECItem *value)
646 {
647 SEC_PKCS7SignerInfo **signerinfos;
648 SEC_PKCS7Attribute *attr;
649
650 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
651 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
652 return SECFailure;
653
654 signerinfos = cinfo->content.signedData->signerInfos;
655
656 /*
657 * No signature or more than one means no deal.
658 */
659 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
660 return SECFailure;
661
662 attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE);
663 if (attr == NULL)
664 return SECFailure;
665
666 return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr);
667 }
668
669
670 /*
671 * Mark that the signer certificates and their issuing chain should
672 * be included in the encoded data. This is expected to be used
673 * in outgoing signed messages for email (S/MIME).
674 *
675 * "certdb" is the cert database to use for finding the chain.
676 * It can be NULL, meaning use the default database.
677 *
678 * "cinfo" should be of type signedData or signedAndEnvelopedData;
679 * SECFailure will be returned if it is not.
680 */
681 SECStatus
682 SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
683 CERTCertDBHandle *certdb)
684 {
685 SECOidTag kind;
686 SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
687
688 kind = SEC_PKCS7ContentType (cinfo);
689 switch (kind) {
690 case SEC_OID_PKCS7_SIGNED_DATA:
691 signerinfos = cinfo->content.signedData->signerInfos;
692 break;
693 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
694 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
695 break;
696 default:
697 return SECFailure; /* XXX set an error? */
698 }
699
700 if (signerinfos == NULL) /* no signer, no certs? */
701 return SECFailure; /* XXX set an error? */
702
703 if (certdb == NULL) {
704 certdb = CERT_GetDefaultCertDB();
705 if (certdb == NULL) {
706 PORT_SetError (SEC_ERROR_BAD_DATABASE);
707 return SECFailure;
708 }
709 }
710
711 /* XXX Should it be an error if we find no signerinfo or no certs? */
712 while ((signerinfo = *signerinfos++) != NULL) {
713 if (signerinfo->cert != NULL)
714 /* get the cert chain. don't send the root to avoid contamination
715 * of old clients with a new root that they don't trust
716 */
717 signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert,
718 certUsageEmailSigner,
719 PR_FALSE);
720 }
721
722 return SECSuccess;
723 }
724
725
726 /*
727 * Helper function to add a certificate chain for inclusion in the
728 * bag of certificates in a signedData.
729 */
730 static SECStatus
731 sec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo,
732 CERTCertificate *cert,
733 CERTCertDBHandle *certdb)
734 {
735 SECOidTag kind;
736 CERTCertificateList *certlist, **certlists, ***certlistsp;
737 int count;
738
739 kind = SEC_PKCS7ContentType (cinfo);
740 switch (kind) {
741 case SEC_OID_PKCS7_SIGNED_DATA:
742 {
743 SEC_PKCS7SignedData *sdp;
744
745 sdp = cinfo->content.signedData;
746 certlistsp = &(sdp->certLists);
747 }
748 break;
749 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
750 {
751 SEC_PKCS7SignedAndEnvelopedData *saedp;
752
753 saedp = cinfo->content.signedAndEnvelopedData;
754 certlistsp = &(saedp->certLists);
755 }
756 break;
757 default:
758 return SECFailure; /* XXX set an error? */
759 }
760
761 if (certdb == NULL) {
762 certdb = CERT_GetDefaultCertDB();
763 if (certdb == NULL) {
764 PORT_SetError (SEC_ERROR_BAD_DATABASE);
765 return SECFailure;
766 }
767 }
768
769 certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE);
770 if (certlist == NULL)
771 return SECFailure;
772
773 certlists = *certlistsp;
774 if (certlists == NULL) {
775 count = 0;
776 certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp,
777 2 * sizeof(CERTCertificateList *));
778 } else {
779 for (count = 0; certlists[count] != NULL; count++)
780 ;
781 PORT_Assert (count); /* should be at least one already */
782 certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp,
783 certlists,
784 (count + 1) * sizeof(CERTCertificateList *),
785 (count + 2) * sizeof(CERTCertificateList *));
786 }
787
788 if (certlists == NULL) {
789 CERT_DestroyCertificateList (certlist);
790 return SECFailure;
791 }
792
793 certlists[count] = certlist;
794 certlists[count + 1] = NULL;
795
796 *certlistsp = certlists;
797
798 return SECSuccess;
799 }
800
801
802 /*
803 * Helper function to add a certificate for inclusion in the bag of
804 * certificates in a signedData.
805 */
806 static SECStatus
807 sec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo,
808 CERTCertificate *cert)
809 {
810 SECOidTag kind;
811 CERTCertificate **certs, ***certsp;
812 int count;
813
814 kind = SEC_PKCS7ContentType (cinfo);
815 switch (kind) {
816 case SEC_OID_PKCS7_SIGNED_DATA:
817 {
818 SEC_PKCS7SignedData *sdp;
819
820 sdp = cinfo->content.signedData;
821 certsp = &(sdp->certs);
822 }
823 break;
824 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
825 {
826 SEC_PKCS7SignedAndEnvelopedData *saedp;
827
828 saedp = cinfo->content.signedAndEnvelopedData;
829 certsp = &(saedp->certs);
830 }
831 break;
832 default:
833 return SECFailure; /* XXX set an error? */
834 }
835
836 cert = CERT_DupCertificate (cert);
837 if (cert == NULL)
838 return SECFailure;
839
840 certs = *certsp;
841 if (certs == NULL) {
842 count = 0;
843 certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp,
844 2 * sizeof(CERTCertificate *));
845 } else {
846 for (count = 0; certs[count] != NULL; count++)
847 ;
848 PORT_Assert (count); /* should be at least one already */
849 certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs,
850 (count + 1) * sizeof(CERTCertificate *),
851 (count + 2) * sizeof(CERTCertificate *));
852 }
853
854 if (certs == NULL) {
855 CERT_DestroyCertificate (cert);
856 return SECFailure;
857 }
858
859 certs[count] = cert;
860 certs[count + 1] = NULL;
861
862 *certsp = certs;
863
864 return SECSuccess;
865 }
866
867
868 /*
869 * Create a PKCS7 certs-only container.
870 *
871 * "cert" is the (first) cert that will be included.
872 *
873 * "include_chain" specifies whether the entire chain for "cert" should
874 * be included.
875 *
876 * "certdb" is the cert database to use for finding the chain.
877 * It can be NULL in when "include_chain" is false, or when meaning
878 * use the default database.
879 *
880 * More certs and chains can be added via AddCertificate and AddCertChain.
881 *
882 * An error results in a return value of NULL and an error set.
883 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
884 */
885 SEC_PKCS7ContentInfo *
886 SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
887 PRBool include_chain,
888 CERTCertDBHandle *certdb)
889 {
890 SEC_PKCS7ContentInfo *cinfo;
891 SECStatus rv;
892
893 cinfo = sec_pkcs7_create_signed_data (NULL, NULL);
894 if (cinfo == NULL)
895 return NULL;
896
897 if (include_chain)
898 rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
899 else
900 rv = sec_pkcs7_add_certificate (cinfo, cert);
901
902 if (rv != SECSuccess) {
903 SEC_PKCS7DestroyContentInfo (cinfo);
904 return NULL;
905 }
906
907 return cinfo;
908 }
909
910
911 /*
912 * Add "cert" and its entire chain to the set of certs included in "cinfo".
913 *
914 * "certdb" is the cert database to use for finding the chain.
915 * It can be NULL, meaning use the default database.
916 *
917 * "cinfo" should be of type signedData or signedAndEnvelopedData;
918 * SECFailure will be returned if it is not.
919 */
920 SECStatus
921 SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
922 CERTCertificate *cert,
923 CERTCertDBHandle *certdb)
924 {
925 SECOidTag kind;
926
927 kind = SEC_PKCS7ContentType (cinfo);
928 if (kind != SEC_OID_PKCS7_SIGNED_DATA
929 && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
930 return SECFailure; /* XXX set an error? */
931
932 return sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
933 }
934
935
936 /*
937 * Add "cert" to the set of certs included in "cinfo".
938 *
939 * "cinfo" should be of type signedData or signedAndEnvelopedData;
940 * SECFailure will be returned if it is not.
941 */
942 SECStatus
943 SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert)
944 {
945 SECOidTag kind;
946
947 kind = SEC_PKCS7ContentType (cinfo);
948 if (kind != SEC_OID_PKCS7_SIGNED_DATA
949 && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
950 return SECFailure; /* XXX set an error? */
951
952 return sec_pkcs7_add_certificate (cinfo, cert);
953 }
954
955
956 static SECStatus
957 sec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo,
958 PLArenaPool *poolp,
959 SECOidTag kind, PRBool detached,
960 SECOidTag encalg, int keysize)
961 {
962 SECStatus rv;
963
964 PORT_Assert (enccinfo != NULL && poolp != NULL);
965 if (enccinfo == NULL || poolp == NULL)
966 return SECFailure;
967
968 /*
969 * XXX Some day we may want to allow for other kinds. That needs
970 * more work and modifications to the creation interface, etc.
971 * For now, allow but notice callers who pass in other kinds.
972 * They are responsible for creating the inner type and encoding,
973 * if it is other than DATA.
974 */
975 PORT_Assert (kind == SEC_OID_PKCS7_DATA);
976
977 enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
978 PORT_Assert (enccinfo->contentTypeTag
979 && enccinfo->contentTypeTag->offset == kind);
980
981 rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType),
982 &(enccinfo->contentTypeTag->oid));
983 if (rv != SECSuccess)
984 return rv;
985
986 /* Save keysize and algorithm for later. */
987 enccinfo->keysize = keysize;
988 enccinfo->encalg = encalg;
989
990 return SECSuccess;
991 }
992
993
994 /*
995 * Add a recipient to a PKCS7 thing, verifying their cert first.
996 * Any error returns SECFailure.
997 */
998 static SECStatus
999 sec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo,
1000 CERTCertificate *cert,
1001 SECCertUsage certusage,
1002 CERTCertDBHandle *certdb)
1003 {
1004 SECOidTag kind;
1005 SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp;
1006 SECItem *dummy;
1007 void *mark;
1008 int count;
1009
1010 kind = SEC_PKCS7ContentType (cinfo);
1011 switch (kind) {
1012 case SEC_OID_PKCS7_ENVELOPED_DATA:
1013 {
1014 SEC_PKCS7EnvelopedData *edp;
1015
1016 edp = cinfo->content.envelopedData;
1017 recipientinfosp = &(edp->recipientInfos);
1018 }
1019 break;
1020 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1021 {
1022 SEC_PKCS7SignedAndEnvelopedData *saedp;
1023
1024 saedp = cinfo->content.signedAndEnvelopedData;
1025 recipientinfosp = &(saedp->recipientInfos);
1026 }
1027 break;
1028 default:
1029 return SECFailure; /* XXX set an error? */
1030 }
1031
1032 /*
1033 * XXX I think that CERT_VerifyCert should do this if *it* is passed
1034 * a NULL database.
1035 */
1036 if (certdb == NULL) {
1037 certdb = CERT_GetDefaultCertDB();
1038 if (certdb == NULL)
1039 return SECFailure; /* XXX set an error? */
1040 }
1041
1042 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
1043 cinfo->pwfn_arg, NULL) != SECSuccess)
1044 {
1045 /* XXX Did CERT_VerifyCert set an error? */
1046 return SECFailure;
1047 }
1048
1049 mark = PORT_ArenaMark (cinfo->poolp);
1050
1051 recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp,
1052 sizeof(SEC_PKCS7RecipientInfo));
1053 if (recipientinfo == NULL) {
1054 PORT_ArenaRelease (cinfo->poolp, mark);
1055 return SECFailure;
1056 }
1057
1058 dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version,
1059 SEC_PKCS7_RECIPIENT_INFO_VERSION);
1060 if (dummy == NULL) {
1061 PORT_ArenaRelease (cinfo->poolp, mark);
1062 return SECFailure;
1063 }
1064 PORT_Assert (dummy == &recipientinfo->version);
1065
1066 recipientinfo->cert = CERT_DupCertificate (cert);
1067 if (recipientinfo->cert == NULL) {
1068 PORT_ArenaRelease (cinfo->poolp, mark);
1069 return SECFailure;
1070 }
1071
1072 recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
1073 if (recipientinfo->issuerAndSN == NULL) {
1074 PORT_ArenaRelease (cinfo->poolp, mark);
1075 return SECFailure;
1076 }
1077
1078 /*
1079 * Okay, now recipientinfo is all set. We just need to put it into
1080 * the main structure.
1081 *
1082 * If this is the first recipient, allocate a new recipientinfos array;
1083 * otherwise, reallocate the array, making room for the new entry.
1084 */
1085 recipientinfos = *recipientinfosp;
1086 if (recipientinfos == NULL) {
1087 count = 0;
1088 recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc (
1089 cinfo->poolp,
1090 2 * sizeof(SEC_PKCS7RecipientInfo *));
1091 } else {
1092 for (count = 0; recipientinfos[count] != NULL; count++)
1093 ;
1094 PORT_Assert (count); /* should be at least one already */
1095 recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow (
1096 cinfo->poolp, recipientinfos,
1097 (count + 1) * sizeof(SEC_PKCS7RecipientInfo *),
1098 (count + 2) * sizeof(SEC_PKCS7RecipientInfo *));
1099 }
1100
1101 if (recipientinfos == NULL) {
1102 PORT_ArenaRelease (cinfo->poolp, mark);
1103 return SECFailure;
1104 }
1105
1106 recipientinfos[count] = recipientinfo;
1107 recipientinfos[count + 1] = NULL;
1108
1109 *recipientinfosp = recipientinfos;
1110
1111 PORT_ArenaUnmark (cinfo->poolp, mark);
1112 return SECSuccess;
1113 }
1114
1115
1116 /*
1117 * Start a PKCS7 enveloping context.
1118 *
1119 * "cert" is the cert for the recipient. It will be checked for validity.
1120 *
1121 * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
1122 * XXX Maybe SECCertUsage should be split so that our caller just says
1123 * "email" and *we* add the "recipient" part -- otherwise our caller
1124 * could be lying about the usage; we do not want to allow encryption
1125 * certs for signing or vice versa.
1126 *
1127 * "certdb" is the cert database to use for verifying the cert.
1128 * It can be NULL if a default database is available (like in the client).
1129 *
1130 * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
1131 *
1132 * "keysize" specifies the bulk encryption key size, in bits.
1133 *
1134 * The return value can be passed to functions which add things to
1135 * it like more recipients, then eventually to SEC_PKCS7Encode() or to
1136 * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
1137 * SEC_PKCS7DestroyContentInfo().
1138 *
1139 * An error results in a return value of NULL and an error set.
1140 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
1141 */
1142 extern SEC_PKCS7ContentInfo *
1143 SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
1144 SECCertUsage certusage,
1145 CERTCertDBHandle *certdb,
1146 SECOidTag encalg,
1147 int keysize,
1148 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
1149 {
1150 SEC_PKCS7ContentInfo *cinfo;
1151 SEC_PKCS7EnvelopedData *envd;
1152 SECStatus rv;
1153
1154 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA,
1155 PR_FALSE, pwfn, pwfn_arg);
1156 if (cinfo == NULL)
1157 return NULL;
1158
1159 rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
1160 if (rv != SECSuccess) {
1161 SEC_PKCS7DestroyContentInfo (cinfo);
1162 return NULL;
1163 }
1164
1165 envd = cinfo->content.envelopedData;
1166 PORT_Assert (envd != NULL);
1167
1168 /*
1169 * XXX Might we want to allow content types other than data?
1170 * If so, via what interface?
1171 */
1172 rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo),
1173 cinfo->poolp,
1174 SEC_OID_PKCS7_DATA, PR_FALSE,
1175 encalg, keysize);
1176 if (rv != SECSuccess) {
1177 SEC_PKCS7DestroyContentInfo (cinfo);
1178 return NULL;
1179 }
1180
1181 /* XXX Anything more to do here? */
1182
1183 return cinfo;
1184 }
1185
1186
1187 /*
1188 * Add another recipient to an encrypted message.
1189 *
1190 * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
1191 * SECFailure will be returned if it is not.
1192 *
1193 * "cert" is the cert for the recipient. It will be checked for validity.
1194 *
1195 * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
1196 * XXX Maybe SECCertUsage should be split so that our caller just says
1197 * "email" and *we* add the "recipient" part -- otherwise our caller
1198 * could be lying about the usage; we do not want to allow encryption
1199 * certs for signing or vice versa.
1200 *
1201 * "certdb" is the cert database to use for verifying the cert.
1202 * It can be NULL if a default database is available (like in the client).
1203 */
1204 SECStatus
1205 SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
1206 CERTCertificate *cert,
1207 SECCertUsage certusage,
1208 CERTCertDBHandle *certdb)
1209 {
1210 return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
1211 }
1212
1213
1214 /*
1215 * Create an empty PKCS7 data content info.
1216 *
1217 * An error results in a return value of NULL and an error set.
1218 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
1219 */
1220 SEC_PKCS7ContentInfo *
1221 SEC_PKCS7CreateData (void)
1222 {
1223 return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE,
1224 NULL, NULL);
1225 }
1226
1227
1228 /*
1229 * Create an empty PKCS7 encrypted content info.
1230 *
1231 * "algorithm" specifies the bulk encryption algorithm to use.
1232 *
1233 * An error results in a return value of NULL and an error set.
1234 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
1235 */
1236 SEC_PKCS7ContentInfo *
1237 SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
1238 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
1239 {
1240 SEC_PKCS7ContentInfo *cinfo;
1241 SECAlgorithmID *algid;
1242 SEC_PKCS7EncryptedData *enc_data;
1243 SECStatus rv;
1244
1245 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA,
1246 PR_FALSE, pwfn, pwfn_arg);
1247 if (cinfo == NULL)
1248 return NULL;
1249
1250 enc_data = cinfo->content.encryptedData;
1251 algid = &(enc_data->encContentInfo.contentEncAlg);
1252
1253 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
1254 rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL);
1255 } else {
1256 /* Assume password-based-encryption.
1257 * Note: we can't generate pkcs5v2 from this interface.
1258 * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
1259 * non-PBE oids and assuming that they are pkcs5v2 oids, but
1260 * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
1261 * CMS encrypted data, so we can't tell SEC_PKCS7CreateEncryptedtedData
1262 * to create pkcs5v2 PBEs */
1263 SECAlgorithmID *pbe_algid;
1264 pbe_algid = PK11_CreatePBEAlgorithmID(algorithm,
1265 NSS_PBE_DEFAULT_ITERATION_COUNT,
1266 NULL);
1267 if (pbe_algid == NULL) {
1268 rv = SECFailure;
1269 } else {
1270 rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid);
1271 SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
1272 }
1273 }
1274
1275 if (rv != SECSuccess) {
1276 SEC_PKCS7DestroyContentInfo (cinfo);
1277 return NULL;
1278 }
1279
1280 rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo),
1281 cinfo->poolp,
1282 SEC_OID_PKCS7_DATA, PR_FALSE,
1283 algorithm, keysize);
1284 if (rv != SECSuccess) {
1285 SEC_PKCS7DestroyContentInfo (cinfo);
1286 return NULL;
1287 }
1288
1289 return cinfo;
1290 }
1291
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)