1 /* mount.c - Mount a crypto container
2 * Copyright (C) 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
40 /* Parse the header prefix and return the length of the entire header. */
42 parse_header (const char *filename
,
43 const unsigned char *packet
, size_t packetlen
,
49 return gpg_error (GPG_ERR_BUG
);
51 len
= ((packet
[2] << 24) | (packet
[3] << 16)
52 | (packet
[4] << 8) | packet
[5]);
53 if (packet
[0] != (0xc0|61) || len
< 26
54 || memcmp (packet
+6, "GnuPG/G13", 10))
56 log_error ("file `%s' is not valid container\n", filename
);
57 return gpg_error (GPG_ERR_INV_OBJ
);
61 log_error ("unknown version %u of container `%s'\n",
62 (unsigned int)packet
[16], filename
);
63 return gpg_error (GPG_ERR_INV_OBJ
);
65 if (packet
[17] || packet
[18]
66 || packet
[26] || packet
[27] || packet
[28] || packet
[29]
67 || packet
[30] || packet
[31])
68 log_info ("WARNING: unknown meta information in `%s'\n", filename
);
70 log_info ("WARNING: OS flag is not supported in `%s'\n", filename
);
71 if (packet
[24] != 1 || packet
[25] != 0)
73 log_error ("meta data copies in `%s' are not supported\n", filename
);
74 return gpg_error (GPG_ERR_NOT_IMPLEMENTED
);
77 len
= ((packet
[20] << 24) | (packet
[21] << 16)
78 | (packet
[22] << 8) | packet
[23]);
80 /* Do a basic sanity check on the length. */
81 if (len
< 32 || len
> 1024*1024)
83 log_error ("bad length given in container `%s'\n", filename
);
84 return gpg_error (GPG_ERR_INV_OBJ
);
93 /* Read the keyblob at FILENAME. The caller should have acquired a
94 lockfile and checked that the file exists. */
96 read_keyblob (const char *filename
,
97 void **r_enckeyblob
, size_t *r_enckeybloblen
)
101 unsigned char packet
[32];
102 size_t headerlen
, msglen
;
105 *r_enckeyblob
= NULL
;
106 *r_enckeybloblen
= 0;
108 fp
= es_fopen (filename
, "rb");
111 err
= gpg_error_from_syserror ();
112 log_error ("error reading `%s': %s\n",
113 filename
, gpg_strerror (err
));
117 /* Read the header. It is defined as 32 bytes thus we read it in one go. */
118 if (es_fread (packet
, 32, 1, fp
) != 1)
120 err
= gpg_error_from_syserror ();
121 log_error ("error reading the header of `%s': %s\n",
122 filename
, gpg_strerror (err
));
126 err
= parse_header (filename
, packet
, 32, &headerlen
);
131 log_info ("header length of `%s' is %zu\n", filename
, headerlen
);
133 /* Read everything including the padding. We should eventually do a
134 regular OpenPGP parsing to detect the padding packet and pass
135 only the actual used OpenPGP data to the engine. This is in
136 particular required when supporting CMS which will be
137 encapsulated in an OpenPGP packet. */
138 assert (headerlen
>= 32);
139 msglen
= headerlen
- 32;
142 err
= gpg_error (GPG_ERR_NO_DATA
);
145 msg
= xtrymalloc (msglen
);
148 err
= gpg_error_from_syserror ();
151 if (es_fread (msg
, msglen
, 1, fp
) != 1)
153 err
= gpg_error_from_syserror ();
154 log_error ("error reading keyblob of `%s': %s\n",
155 filename
, gpg_strerror (err
));
161 *r_enckeybloblen
= msglen
;
173 /* Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result at
174 (R_KEYBLOB, R_KEYBLOBLEN). Returns 0 on success or an error code.
175 On error R_KEYBLOB is set to NULL. */
177 decrypt_keyblob (ctrl_t ctrl
, const void *enckeyblob
, size_t enckeybloblen
,
178 void **r_keyblob
, size_t *r_keybloblen
)
182 /* FIXME: For now we only implement OpenPGP. */
183 err
= gpg_decrypt_blob (ctrl
, enckeyblob
, enckeybloblen
,
184 r_keyblob
, r_keybloblen
);
191 dump_keyblob (tupledesc_t tuples
)
197 log_info ("keyblob dump:\n");
198 tag
= KEYBLOB_TAG_BLOBVERSION
;
199 value
= find_tuple (tuples
, tag
, &n
);
202 log_info (" tag: %-5u len: %-2u value: ", tag
, (unsigned int)n
);
203 if (tag
== KEYBLOB_TAG_ENCKEY
204 || tag
== KEYBLOB_TAG_MACKEY
)
205 log_printf ("[confidential]\n");
207 log_printf ("[none]\n");
209 log_printhex ("", value
, n
);
210 value
= next_tuple (tuples
, &tag
, &n
);
216 /* Mount the container with name FILENAME at MOUNTPOINT. */
218 g13_mount_container (ctrl_t ctrl
, const char *filename
, const char *mountpoint
)
222 void *enckeyblob
= NULL
;
223 size_t enckeybloblen
;
224 void *keyblob
= NULL
;
226 tupledesc_t tuples
= NULL
;
228 const unsigned char *value
;
231 /* A quick check to see whether the container exists. */
232 if (access (filename
, R_OK
))
233 return gpg_error_from_syserror ();
235 /* Try to take a lock. */
236 lock
= create_dotlock (filename
);
238 return gpg_error_from_syserror ();
240 if (make_dotlock (lock
, 0))
242 err
= gpg_error_from_syserror ();
248 /* Check again that the file exists. */
252 if (stat (filename
, &sb
))
254 err
= gpg_error_from_syserror ();
259 /* Read the encrypted keyblob. */
260 err
= read_keyblob (filename
, &enckeyblob
, &enckeybloblen
);
264 /* Decrypt that keyblob and store it in a tuple descriptor. */
265 err
= decrypt_keyblob (ctrl
, enckeyblob
, enckeybloblen
,
266 &keyblob
, &keybloblen
);
272 err
= create_tupledesc (&tuples
, keyblob
, keybloblen
);
277 if (gpg_err_code (err
) == GPG_ERR_NOT_SUPPORTED
)
278 log_error ("unknown keyblob version\n");
282 dump_keyblob (tuples
);
284 value
= find_tuple (tuples
, KEYBLOB_TAG_CONTTYPE
, &n
);
285 if (!value
|| n
!= 2)
288 conttype
= (value
[0] << 8 | value
[1]);
289 if (!be_is_supported_conttype (conttype
))
291 log_error ("content type %d is not supported\n", conttype
);
292 err
= gpg_error (GPG_ERR_NOT_SUPPORTED
);
295 err
= be_mount_container (ctrl
, conttype
, filename
, mountpoint
, tuples
);
298 destroy_tupledesc (tuples
);
301 destroy_dotlock (lock
);