summaryrefslogtreecommitdiff
path: root/doc/examples/ex-pkcs12.c
blob: 0be058e924f3789f32f1acce9ec3b6c3571c73ce (plain)
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
/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>
#include <gnutls/pkcs12.h>

#include "examples.h"

#define OUTFILE "out.p12"

/* This function will write a pkcs12 structure into a file.
 * cert: is a DER encoded certificate
 * pkcs8_key: is a PKCS #8 encrypted key (note that this must be
 *  encrypted using a PKCS #12 cipher, or some browsers will crash)
 * password: is the password used to encrypt the PKCS #12 packet.
 */
int
write_pkcs12 (const gnutls_datum_t * cert,
              const gnutls_datum_t * pkcs8_key, const char *password)
{
  gnutls_pkcs12_t pkcs12;
  int ret, bag_index;
  gnutls_pkcs12_bag_t bag, key_bag;
  char pkcs12_struct[10 * 1024];
  size_t pkcs12_struct_size;
  FILE *fd;

  /* A good idea might be to use gnutls_x509_privkey_get_key_id()
   * to obtain a unique ID.
   */
  gnutls_datum_t key_id = { (char *) "\x00\x00\x07", 3 };

  gnutls_global_init ();

  /* Firstly we create two helper bags, which hold the certificate,
   * and the (encrypted) key.
   */

  gnutls_pkcs12_bag_init (&bag);
  gnutls_pkcs12_bag_init (&key_bag);

  ret = gnutls_pkcs12_bag_set_data (bag, GNUTLS_BAG_CERTIFICATE, cert);
  if (ret < 0)
    {
      fprintf (stderr, "ret: %s\n", gnutls_strerror (ret));
      return 1;
    }

  /* ret now holds the bag's index.
   */
  bag_index = ret;

  /* Associate a friendly name with the given certificate. Used
   * by browsers.
   */
  gnutls_pkcs12_bag_set_friendly_name (bag, bag_index, "My name");

  /* Associate the certificate with the key using a unique key
   * ID.
   */
  gnutls_pkcs12_bag_set_key_id (bag, bag_index, &key_id);

  /* use weak encryption for the certificate. 
   */
  gnutls_pkcs12_bag_encrypt (bag, password, GNUTLS_PKCS_USE_PKCS12_RC2_40);

  /* Now the key.
   */

  ret = gnutls_pkcs12_bag_set_data (key_bag,
                                    GNUTLS_BAG_PKCS8_ENCRYPTED_KEY,
                                    pkcs8_key);
  if (ret < 0)
    {
      fprintf (stderr, "ret: %s\n", gnutls_strerror (ret));
      return 1;
    }

  /* Note that since the PKCS #8 key is already encrypted we don't
   * bother encrypting that bag.
   */
  bag_index = ret;

  gnutls_pkcs12_bag_set_friendly_name (key_bag, bag_index, "My name");

  gnutls_pkcs12_bag_set_key_id (key_bag, bag_index, &key_id);


  /* The bags were filled. Now create the PKCS #12 structure.
   */
  gnutls_pkcs12_init (&pkcs12);

  /* Insert the two bags in the PKCS #12 structure.
   */

  gnutls_pkcs12_set_bag (pkcs12, bag);
  gnutls_pkcs12_set_bag (pkcs12, key_bag);


  /* Generate a message authentication code for the PKCS #12
   * structure.
   */
  gnutls_pkcs12_generate_mac (pkcs12, password);

  pkcs12_struct_size = sizeof (pkcs12_struct);
  ret =
    gnutls_pkcs12_export (pkcs12, GNUTLS_X509_FMT_DER, pkcs12_struct,
                          &pkcs12_struct_size);
  if (ret < 0)
    {
      fprintf (stderr, "ret: %s\n", gnutls_strerror (ret));
      return 1;
    }

  fd = fopen (OUTFILE, "w");
  if (fd == NULL)
    {
      fprintf (stderr, "cannot open file\n");
      return 1;
    }
  fwrite (pkcs12_struct, 1, pkcs12_struct_size, fd);
  fclose (fd);

  gnutls_pkcs12_bag_deinit (bag);
  gnutls_pkcs12_bag_deinit (key_bag);
  gnutls_pkcs12_deinit (pkcs12);

  return 0;
}