diff --git a/deltachat-core.cbp b/deltachat-core.cbp
index 81963afb..18b16598 100644
--- a/deltachat-core.cbp
+++ b/deltachat-core.cbp
@@ -54,6 +54,8 @@
+
+
@@ -371,6 +373,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/netpgp/include/netpgp.h b/libs/netpgp/include/netpgp.h
new file mode 100644
index 00000000..0378697e
--- /dev/null
+++ b/libs/netpgp/include/netpgp.h
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@netbsd.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NETPGP_H_
+#define NETPGP_H_
+
+#ifndef __BEGIN_DECLS
+# if defined(__cplusplus)
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+# else
+# define __BEGIN_DECLS
+# define __END_DECLS
+# endif
+#endif
+
+__BEGIN_DECLS
+
+/* structure used to hold (key,value) pair information */
+typedef struct netpgp_t {
+ unsigned c; /* # of elements used */
+ unsigned size; /* size of array */
+ char **name; /* key names */
+ char **value; /* value information */
+ void *pubring; /* public key ring */
+ void *secring; /* s3kr1t key ring */
+ void *io; /* the io struct for results/errs */
+ void *passfp; /* file pointer for password input */
+} netpgp_t;
+
+/* begin and end */
+int netpgp_init(netpgp_t *);
+int netpgp_end(netpgp_t *);
+
+/* debugging, reflection and information */
+int netpgp_set_debug(const char *);
+int netpgp_get_debug(const char *);
+const char *netpgp_get_info(const char *);
+int netpgp_list_packets(netpgp_t *, char *, int, char *);
+
+/* variables */
+int netpgp_setvar(netpgp_t *, const char *, const char *);
+char *netpgp_getvar(netpgp_t *, const char *);
+int netpgp_incvar(netpgp_t *, const char *, const int);
+int netpgp_unsetvar(netpgp_t *, const char *);
+
+/* set home directory information */
+int netpgp_set_homedir(netpgp_t *, char *, const char *, const int);
+
+/* key management */
+int netpgp_list_keys(netpgp_t *, const int);
+int netpgp_list_keys_json(netpgp_t *, char **, const int);
+int netpgp_find_key(netpgp_t *, char *);
+char *netpgp_get_key(netpgp_t *, const char *, const char *);
+char *netpgp_export_key(netpgp_t *, char *);
+int netpgp_import_key(netpgp_t *, char *);
+int netpgp_generate_key(netpgp_t *, char *, int);
+
+/* file management */
+int netpgp_encrypt_file(netpgp_t *, const char *, const char *, char *, int);
+int netpgp_decrypt_file(netpgp_t *, const char *, char *, int);
+int netpgp_sign_file(netpgp_t *, const char *, const char *, char *, int, int, int);
+int netpgp_verify_file(netpgp_t *, const char *, const char *, int);
+
+/* memory signing and encryption */
+int netpgp_sign_memory(netpgp_t *, const char *, char *, size_t, char *, size_t, const unsigned, const unsigned);
+int netpgp_verify_memory(netpgp_t *, const void *, const size_t, void *, size_t, const int);
+int netpgp_encrypt_memory(netpgp_t *, const char *, void *, const size_t, char *, size_t, int);
+int netpgp_decrypt_memory(netpgp_t *, const void *, const size_t, char *, size_t, const int);
+
+/* match and hkp-related functions */
+int netpgp_match_keys_json(netpgp_t *, char **, char *, const char *, const int);
+int netpgp_match_keys(netpgp_t *, char *, const char *, void *, const int);
+int netpgp_match_pubkeys(netpgp_t *, char *, void *);
+int netpgp_format_json(void *, const char *, const int);
+
+int netpgp_validate_sigs(netpgp_t *);
+
+/* save pgp key in ssh format */
+int netpgp_write_sshkey(netpgp_t *, char *, const char *, char *, size_t);
+
+
+__END_DECLS
+
+#endif /* !NETPGP_H_ */
diff --git a/libs/netpgp/src/lib/bufgap.c b/libs/netpgp/src/lib/bufgap.c
new file mode 100644
index 00000000..863221b3
--- /dev/null
+++ b/libs/netpgp/src/lib/bufgap.c
@@ -0,0 +1,519 @@
+/* $NetBSD: bufgap.c,v 1.5 2010/11/29 06:21:40 agc Exp $ */
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include
+#endif
+
+#include
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_STRING_H
+#include
+#endif
+
+#include "bufgap.h"
+#include "defs.h"
+
+/* macros to get subscripts in buffer */
+#define AFTSUB(bp, n) ((bp)->buf[(int)n])
+#define BEFSUB(bp, n) ((bp)->buf[(int)((bp)->size - (n) - 1)])
+
+/* initial allocation size */
+#ifndef CHUNKSIZE
+#define CHUNKSIZE 256
+#endif
+
+#ifndef KiB
+#define KiB(x) ((x) * 1024)
+#endif
+
+#define BGCHUNKSIZE KiB(4)
+
+#ifndef __UNCONST
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif
+
+#ifndef USE_UTF
+#define USE_UTF 0
+#endif
+
+#if !USE_UTF
+#define Rune char
+#define utfbytes(x) strlen(x)
+#define utfrune(a, b) strchr(a, b)
+#define utfnlen(a, b) bounded_strlen(a, b)
+
+static size_t
+bounded_strlen(const char *s, size_t maxlen)
+{
+ size_t n;
+
+ for (n = 0 ; n < maxlen && s[n] != 0x0 ; n++) {
+ }
+ return n;
+}
+
+static int
+chartorune(Rune *rp, char *s)
+{
+ *rp = s[0];
+ return 1;
+}
+
+static int
+priorrune(Rune *rp, char *s)
+{
+ *rp = s[0];
+ return 1;
+}
+#else
+#include "ure.h"
+#endif
+
+/* save `n' chars of `s' in malloc'd memory */
+static char *
+strnsave(char *s, int n)
+{
+ char *cp;
+
+ if (n < 0) {
+ n = (int)strlen(s);
+ }
+ NEWARRAY(char, cp, n + 1, "strnsave", return NULL);
+ (void) memcpy(cp, s, (size_t)n);
+ cp[n] = 0x0;
+ return cp;
+}
+
+/* open a file in a buffer gap structure */
+int
+bufgap_open(bufgap_t *bp, const char *f)
+{
+ struct stat s;
+ int64_t cc;
+ FILE *filep;
+ char *cp;
+
+ (void) memset(bp, 0x0, sizeof(*bp));
+ filep = NULL;
+ if (f != NULL && (filep = fopen(f, "r")) == NULL) {
+ return 0;
+ }
+ if (f == NULL) {
+ bp->size = BGCHUNKSIZE;
+ NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
+ } else {
+ (void) fstat(fileno(filep), &s);
+ bp->size = (int) ((s.st_size / BGCHUNKSIZE) + 1) * BGCHUNKSIZE;
+ NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
+ cc = fread(&BEFSUB(bp, s.st_size), sizeof(char),
+ (size_t)s.st_size, filep);
+ (void) fclose(filep);
+ if (cc != s.st_size) {
+ FREE(bp->buf);
+ FREE(bp);
+ return 0;
+ }
+ bp->name = strnsave(__UNCONST(f), (int)utfbytes(__UNCONST(f)));
+ bp->bbc = s.st_size;
+ cp = &BEFSUB(bp, cc);
+ for (;;) {
+ if ((cp = utfrune(cp, '\n')) == NULL) {
+ break;
+ }
+ bp->blc++;
+ cp++;
+ }
+ bp->bcc = utfnlen(&BEFSUB(bp, cc), (size_t)cc);
+ }
+ return 1;
+}
+
+/* close a buffer gapped file */
+void
+bufgap_close(bufgap_t *bp)
+{
+ FREE(bp->buf);
+}
+
+/* move forwards `n' chars/bytes in a buffer gap */
+int
+bufgap_forwards(bufgap_t *bp, uint64_t n, int type)
+{
+ Rune r;
+ int rlen;
+
+ switch(type) {
+ case BGChar:
+ if (bp->bcc >= n) {
+ while (n-- > 0) {
+ rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
+ if (rlen == 1) {
+ AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
+ } else {
+ (void) memmove(&AFTSUB(bp, bp->abc),
+ &BEFSUB(bp, bp->bbc),
+ (size_t)rlen);
+ }
+ bp->acc++;
+ bp->bcc--;
+ bp->abc += rlen;
+ bp->bbc -= rlen;
+ if (r == '\n') {
+ bp->alc++;
+ bp->blc--;
+ }
+ }
+ return 1;
+ }
+ break;
+ case BGByte:
+ if (bp->bbc >= n) {
+ for ( ; n > 0 ; n -= rlen) {
+ rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
+ if (rlen == 1) {
+ AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
+ } else {
+ (void) memmove(&AFTSUB(bp, bp->abc),
+ &BEFSUB(bp, bp->bbc),
+ (size_t)rlen);
+ }
+ bp->acc++;
+ bp->bcc--;
+ bp->abc += rlen;
+ bp->bbc -= rlen;
+ if (r == '\n') {
+ bp->alc++;
+ bp->blc--;
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* move backwards `n' chars in a buffer gap */
+int
+bufgap_backwards(bufgap_t *bp, uint64_t n, int type)
+{
+ Rune r;
+ int rlen;
+
+ switch(type) {
+ case BGChar:
+ if (bp->acc >= n) {
+ while (n-- > 0) {
+ rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
+ bp->bcc++;
+ bp->acc--;
+ bp->bbc += rlen;
+ bp->abc -= rlen;
+ if (rlen == 1) {
+ BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
+ } else {
+ (void) memmove(&BEFSUB(bp, bp->bbc),
+ &AFTSUB(bp, bp->abc),
+ (size_t)rlen);
+ }
+ if (r == '\n') {
+ bp->blc++;
+ bp->alc--;
+ }
+ }
+ return 1;
+ }
+ break;
+ case BGByte:
+ if (bp->acc >= n) {
+ for ( ; n > 0 ; n -= rlen) {
+ rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
+ bp->bcc++;
+ bp->acc--;
+ bp->bbc += rlen;
+ bp->abc -= rlen;
+ if (rlen == 1) {
+ BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
+ } else {
+ (void) memmove(&BEFSUB(bp, bp->bbc),
+ &AFTSUB(bp, bp->abc),
+ (size_t)rlen);
+ }
+ if (r == '\n') {
+ bp->blc++;
+ bp->alc--;
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* move within a buffer gap */
+int
+bufgap_seek(bufgap_t *bp, int64_t off, int whence, int type)
+{
+ switch(type) {
+ case BGLine:
+ switch(whence) {
+ case BGFromBOF:
+ if (off < 0 || off > (int64_t)(bp->alc + bp->blc)) {
+ return 0;
+ }
+ if (off < (int64_t)bp->alc) {
+ while (off <= (int64_t)bp->alc && bufgap_backwards(bp, 1, BGChar)) {
+ }
+ if (off > 0) {
+ (void) bufgap_forwards(bp, 1, BGChar);
+ }
+ } else if (off > (int64_t)bp->alc) {
+ while (off > (int64_t)bp->alc && bufgap_forwards(bp, 1, BGChar)) {
+ }
+ }
+ return 1;
+ case BGFromHere:
+ return bufgap_seek(bp, (int64_t)(bp->alc + off), BGFromBOF, BGLine);
+ case BGFromEOF:
+ return bufgap_seek(bp, (int64_t)(bp->alc + bp->blc + off), BGFromBOF, BGLine);
+ }
+ break;
+ case BGChar:
+ switch(whence) {
+ case BGFromBOF:
+ if (off < 0 || off > (int64_t)(bp->acc + bp->bcc)) {
+ return 0;
+ }
+ if (off < (int64_t)bp->acc) {
+ return bufgap_backwards(bp, bp->acc - off, BGChar);
+ } else if (off > (int64_t)bp->acc) {
+ return bufgap_forwards(bp, off - bp->acc, BGChar);
+ }
+ return 1;
+ case BGFromHere:
+ return bufgap_seek(bp, (int64_t)(bp->acc + off), BGFromBOF, BGChar);
+ case BGFromEOF:
+ return bufgap_seek(bp, (int64_t)(bp->acc + bp->bcc + off), BGFromBOF, BGChar);
+ }
+ break;
+ case BGByte:
+ switch(whence) {
+ case BGFromBOF:
+ if (off < 0 || off > (int64_t)(bp->abc + bp->bbc)) {
+ return 0;
+ }
+ if (off < (int64_t)bp->abc) {
+ return bufgap_backwards(bp, bp->abc - off, BGByte);
+ } else if (off > (int64_t)bp->abc) {
+ return bufgap_forwards(bp, off - bp->abc, BGByte);
+ }
+ return 1;
+ case BGFromHere:
+ return bufgap_seek(bp, (int64_t)(bp->abc + off), BGFromBOF, BGByte);
+ case BGFromEOF:
+ return bufgap_seek(bp, (int64_t)(bp->abc + bp->bbc + off), BGFromBOF, BGByte);
+ }
+ break;
+ }
+ return 0;
+}
+
+/* return a pointer to the text in the buffer gap */
+char *
+bufgap_getstr(bufgap_t *bp)
+{
+ return &BEFSUB(bp, bp->bbc);
+}
+
+/* return the binary text in the buffer gap */
+int
+bufgap_getbin(bufgap_t *bp, void *dst, size_t len)
+{
+ int cc;
+
+ cc = (bp->bcc < len) ? (int)bp->bcc : (int)len;
+ (void) memcpy(dst, &BEFSUB(bp, bp->bbc), len);
+ return cc;
+}
+
+/* return offset (from beginning/end) in a buffer gap */
+int64_t
+bufgap_tell(bufgap_t *bp, int whence, int type)
+{
+ switch(whence) {
+ case BGFromBOF:
+ return (type == BGLine) ? bp->alc :
+ (type == BGByte) ? bp->abc : bp->acc;
+ case BGFromEOF:
+ return (type == BGLine) ? bp->blc :
+ (type == BGByte) ? bp->bbc : bp->bcc;
+ default:
+ (void) fprintf(stderr, "weird whence in bufgap_tell\n");
+ break;
+ }
+ return (int64_t)0;
+}
+
+/* return size of buffer gap */
+int64_t
+bufgap_size(bufgap_t *bp, int type)
+{
+ return (type == BGLine) ? bp->alc + bp->blc :
+ (type == BGChar) ? bp->acc + bp->bcc :
+ bp->abc + bp->bbc;
+}
+
+/* insert `n' chars of `s' in a buffer gap */
+int
+bufgap_insert(bufgap_t *bp, const char *s, int n)
+{
+ int64_t off;
+ Rune r;
+ int rlen;
+ int i;
+
+ if (n < 0) {
+ n = (int)strlen(s);
+ }
+ for (i = 0 ; i < n ; i += rlen) {
+ if (bp->bbc + bp->abc == bp->size) {
+ off = bufgap_tell(bp, BGFromBOF, BGChar);
+ (void) bufgap_seek(bp, 0, BGFromEOF, BGChar);
+ bp->size *= 2;
+ RENEW(char, bp->buf, bp->size, "bufgap_insert", return 0);
+ (void) bufgap_seek(bp, off, BGFromBOF, BGChar);
+ }
+ if ((rlen = chartorune(&r, __UNCONST(s))) == 1) {
+ AFTSUB(bp, bp->abc) = *s;
+ } else {
+ (void) memmove(&AFTSUB(bp, bp->abc), s, (size_t)rlen);
+ }
+ if (r == '\n') {
+ bp->alc++;
+ }
+ bp->modified = 1;
+ bp->abc += rlen;
+ bp->acc++;
+ s += rlen;
+ }
+ return 1;
+}
+
+/* delete `n' bytes from the buffer gap */
+int
+bufgap_delete(bufgap_t *bp, uint64_t n)
+{
+ uint64_t i;
+ Rune r;
+ int rlen;
+
+ if (n <= bp->bbc) {
+ for (i = 0 ; i < n ; i += rlen) {
+ rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
+ if (r == '\n') {
+ bp->blc--;
+ }
+ bp->bbc -= rlen;
+ bp->bcc--;
+ bp->modified = 1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* look at a character in a buffer gap `delta' UTF chars away */
+int
+bufgap_peek(bufgap_t *bp, int64_t delta)
+{
+ int ch;
+
+ if (delta != 0) {
+ if (!bufgap_seek(bp, delta, BGFromHere, BGChar)) {
+ return -1;
+ }
+ }
+ ch = BEFSUB(bp, bp->bbc);
+ if (delta != 0) {
+ (void) bufgap_seek(bp, -delta, BGFromHere, BGChar);
+ }
+ return ch;
+}
+
+/* return, in malloc'd storage, text from the buffer gap */
+char *
+bufgap_gettext(bufgap_t *bp, int64_t from, int64_t to)
+{
+ int64_t off;
+ int64_t n;
+ char *text;
+
+ off = bufgap_tell(bp, BGFromBOF, BGChar);
+ NEWARRAY(char, text, (to - from + 1), "bufgap_gettext", return NULL);
+ (void) bufgap_seek(bp, from, BGFromBOF, BGChar);
+ for (n = 0 ; n < to - from ; n++) {
+ text[(int)n] = BEFSUB(bp, bp->bbc - n);
+ }
+ text[(int)n] = 0x0;
+ (void) bufgap_seek(bp, off, BGFromBOF, BGChar);
+ return text;
+}
+
+/* return 1 if we wrote the file correctly */
+int
+bufgap_write(bufgap_t *bp, FILE *filep)
+{
+ if (fwrite(bp->buf, sizeof(char), (size_t)bp->abc, filep) != (size_t)bp->abc) {
+ return 0;
+ }
+ if (fwrite(&BEFSUB(bp, bp->bbc), sizeof(char), (size_t)bp->bbc, filep) != (size_t)bp->bbc) {
+ return 0;
+ }
+ return 1;
+}
+
+/* tell if the buffer gap is dirty - has been modified */
+int
+bufgap_dirty(bufgap_t *bp)
+{
+ return (int)bp->modified;
+}
diff --git a/libs/netpgp/src/lib/bufgap.h b/libs/netpgp/src/lib/bufgap.h
new file mode 100644
index 00000000..461126db
--- /dev/null
+++ b/libs/netpgp/src/lib/bufgap.h
@@ -0,0 +1,88 @@
+/* $NetBSD: bufgap.h,v 1.2 2009/12/06 17:43:05 agc Exp $ */
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef BUFGAP_H_
+#define BUFGAP_H_ 20091023
+
+#include
+
+#include
+#include
+
+#ifndef BUFGAP_VERSION_STRING
+#define BUFGAP_VERSION_STRING "20091022"
+#endif
+
+#ifndef BUFGAP_AUTHOR_STRING
+#define BUFGAP_AUTHOR_STRING "Alistair Crooks (agc@netbsd.org)"
+#endif
+
+/* Constants for Buffer Gap routines */
+enum {
+ BGByte,
+ BGChar,
+ BGLine,
+
+ BGFromBOF,
+ BGFromHere,
+ BGFromEOF
+};
+
+/* this struct describes a file in memory */
+typedef struct bufgap_t {
+ uint64_t size; /* size of file */
+ uint64_t abc; /* # of bytes after the gap */
+ uint64_t bbc; /* # of bytes before the gap */
+ uint64_t acc; /* # of utf chars after the gap */
+ uint64_t bcc; /* # of utf chars before the gap */
+ uint64_t alc; /* # of records after the gap */
+ uint64_t blc; /* # of records before the gap */
+ char *name; /* file name - perhaps null */
+ char *buf; /* buffer-gap buffer */
+ char modified; /* file has been modified */
+} bufgap_t;
+
+int bufgap_open(bufgap_t *, const char *);
+void bufgap_close(bufgap_t *);
+int bufgap_forwards(bufgap_t *, uint64_t, int);
+int bufgap_backwards(bufgap_t *, uint64_t, int);
+int bufgap_seek(bufgap_t *, int64_t, int, int);
+char *bufgap_getstr(bufgap_t *);
+int bufgap_getbin(bufgap_t *, void *, size_t);
+int64_t bufgap_tell(bufgap_t *, int, int);
+int64_t bufgap_size(bufgap_t *, int);
+int bufgap_insert(bufgap_t *, const char *, int);
+int bufgap_delete(bufgap_t *, uint64_t);
+int bufgap_peek(bufgap_t *, int64_t);
+char *bufgap_gettext(bufgap_t *, int64_t, int64_t);
+int bufgap_write(bufgap_t *, FILE *);
+int bufgap_dirty(bufgap_t *);
+
+#endif /* !BUFGAP_H_ */
diff --git a/libs/netpgp/src/lib/compress.c b/libs/netpgp/src/lib/compress.c
new file mode 100644
index 00000000..8bfe81f3
--- /dev/null
+++ b/libs/netpgp/src/lib/compress.c
@@ -0,0 +1,489 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: compress.c,v 1.23 2012/03/05 02:20:18 christos Exp $");
+#endif
+
+#ifdef HAVE_ZLIB_H
+#include
+#endif
+
+#ifdef HAVE_BZLIB_H
+#include
+#endif
+
+#include
+
+#include "packet-parse.h"
+#include "errors.h"
+#include "netpgpdefs.h"
+#include "crypto.h"
+#include "memory.h"
+#include "writer.h"
+
+#define DECOMPRESS_BUFFER 1024
+
+typedef struct {
+ pgp_compression_type_t type;
+ pgp_region_t *region;
+ uint8_t in[DECOMPRESS_BUFFER];
+ uint8_t out[DECOMPRESS_BUFFER];
+ z_stream zstream;/* ZIP and ZLIB */
+ size_t offset;
+ int inflate_ret;
+} z_decompress_t;
+
+#ifdef HAVE_BZLIB_H
+typedef struct {
+ pgp_compression_type_t type;
+ pgp_region_t *region;
+ char in[DECOMPRESS_BUFFER];
+ char out[DECOMPRESS_BUFFER];
+ bz_stream bzstream; /* BZIP2 */
+ size_t offset;
+ int inflate_ret;
+} bz_decompress_t;
+#endif
+
+typedef struct {
+ z_stream stream;
+ uint8_t *src;
+ uint8_t *dst;
+} compress_t;
+
+/*
+ * \todo remove code duplication between this and
+ * bzip2_compressed_data_reader
+ */
+static int
+zlib_compressed_data_reader(pgp_stream_t *stream, void *dest, size_t length,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ z_decompress_t *z = pgp_reader_get_arg(readinfo);
+ size_t len;
+ size_t cc;
+ char *cdest = dest;
+
+ if (z->type != PGP_C_ZIP && z->type != PGP_C_ZLIB) {
+ (void) fprintf(stderr,
+ "zlib_compressed_data_reader: weird type %d\n",
+ z->type);
+ return 0;
+ }
+
+ if (z->inflate_ret == Z_STREAM_END &&
+ z->zstream.next_out == &z->out[z->offset]) {
+ return 0;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr,
+ "zlib_compressed_data_reader: length %" PRIsize "d\n",
+ length);
+ }
+ for (cc = 0 ; cc < length ; cc += len) {
+ if (&z->out[z->offset] == z->zstream.next_out) {
+ int ret;
+
+ z->zstream.next_out = z->out;
+ z->zstream.avail_out = sizeof(z->out);
+ z->offset = 0;
+ if (z->zstream.avail_in == 0) {
+ unsigned n = z->region->length;
+
+ if (!z->region->indeterminate) {
+ n -= z->region->readc;
+ if (n > sizeof(z->in)) {
+ n = sizeof(z->in);
+ }
+ } else {
+ n = sizeof(z->in);
+ }
+ if (!pgp_stacked_limited_read(stream, z->in, n,
+ z->region,
+ errors, readinfo, cbinfo)) {
+ return -1;
+ }
+
+ z->zstream.next_in = z->in;
+ z->zstream.avail_in = (z->region->indeterminate) ?
+ z->region->last_read : n;
+ }
+ ret = inflate(&z->zstream, Z_SYNC_FLUSH);
+ if (ret == Z_STREAM_END) {
+ if (!z->region->indeterminate &&
+ z->region->readc != z->region->length) {
+ PGP_ERROR_1(cbinfo->errors,
+ PGP_E_P_DECOMPRESSION_ERROR,
+ "%s",
+ "Compressed stream ended before packet end.");
+ }
+ } else if (ret != Z_OK) {
+ (void) fprintf(stderr, "ret=%d\n", ret);
+ PGP_ERROR_1(cbinfo->errors,
+ PGP_E_P_DECOMPRESSION_ERROR, "%s",
+ z->zstream.msg);
+ }
+ z->inflate_ret = ret;
+ }
+ if (z->zstream.next_out <= &z->out[z->offset]) {
+ (void) fprintf(stderr, "Out of memory in buffer\n");
+ return 0;
+ }
+ len = (size_t)(z->zstream.next_out - &z->out[z->offset]);
+ if (len > length) {
+ len = length;
+ }
+ (void) memcpy(&cdest[cc], &z->out[z->offset], len);
+ z->offset += len;
+ }
+
+ return (int)length;
+}
+
+#ifdef HAVE_BZLIB_H
+/* \todo remove code duplication between this and zlib_compressed_data_reader */
+static int
+bzip2_compressed_data_reader(pgp_stream_t *stream, void *dest, size_t length,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ bz_decompress_t *bz = pgp_reader_get_arg(readinfo);
+ size_t len;
+ size_t cc;
+ char *cdest = dest;
+
+ if (bz->type != PGP_C_BZIP2) {
+ (void) fprintf(stderr, "Weird type %d\n", bz->type);
+ return 0;
+ }
+ if (bz->inflate_ret == BZ_STREAM_END &&
+ bz->bzstream.next_out == &bz->out[bz->offset]) {
+ return 0;
+ }
+ for (cc = 0 ; cc < length ; cc += len) {
+ if (&bz->out[bz->offset] == bz->bzstream.next_out) {
+ int ret;
+
+ bz->bzstream.next_out = (char *) bz->out;
+ bz->bzstream.avail_out = sizeof(bz->out);
+ bz->offset = 0;
+ if (bz->bzstream.avail_in == 0) {
+ unsigned n = bz->region->length;
+
+ if (!bz->region->indeterminate) {
+ n -= bz->region->readc;
+ if (n > sizeof(bz->in))
+ n = sizeof(bz->in);
+ } else
+ n = sizeof(bz->in);
+
+ if (!pgp_stacked_limited_read(stream,
+ (uint8_t *) bz->in,
+ n, bz->region,
+ errors, readinfo, cbinfo))
+ return -1;
+
+ bz->bzstream.next_in = bz->in;
+ bz->bzstream.avail_in =
+ (bz->region->indeterminate) ?
+ bz->region->last_read : n;
+ }
+ ret = BZ2_bzDecompress(&bz->bzstream);
+ if (ret == BZ_STREAM_END) {
+ if (!bz->region->indeterminate &&
+ bz->region->readc != bz->region->length)
+ PGP_ERROR_1(cbinfo->errors,
+ PGP_E_P_DECOMPRESSION_ERROR,
+ "%s",
+ "Compressed stream ended before packet end.");
+ } else if (ret != BZ_OK) {
+ PGP_ERROR_1(cbinfo->errors,
+ PGP_E_P_DECOMPRESSION_ERROR,
+ "Invalid return %d from BZ2_bzDecompress", ret);
+ }
+ bz->inflate_ret = ret;
+ }
+ if (bz->bzstream.next_out <= &bz->out[bz->offset]) {
+ (void) fprintf(stderr, "Out of bz memroy\n");
+ return 0;
+ }
+ len = (size_t)(bz->bzstream.next_out - &bz->out[bz->offset]);
+ if (len > length) {
+ len = length;
+ }
+ (void) memcpy(&cdest[cc], &bz->out[bz->offset], len);
+ bz->offset += len;
+ }
+
+ return (int)length;
+}
+#endif
+
+/**
+ * \ingroup Core_Compress
+ *
+ * \param *region Pointer to a region
+ * \param *stream How to parse
+ * \param type Which compression type to expect
+*/
+
+int
+pgp_decompress(pgp_region_t *region, pgp_stream_t *stream,
+ pgp_compression_type_t type)
+{
+ z_decompress_t z;
+#ifdef HAVE_BZLIB_H
+ bz_decompress_t bz;
+#endif
+ const int printerrors = 1;
+ int ret;
+
+ switch (type) {
+ case PGP_C_ZIP:
+ case PGP_C_ZLIB:
+ (void) memset(&z, 0x0, sizeof(z));
+
+ z.region = region;
+ z.offset = 0;
+ z.type = type;
+
+ z.zstream.next_in = Z_NULL;
+ z.zstream.avail_in = 0;
+ z.zstream.next_out = z.out;
+ z.zstream.zalloc = Z_NULL;
+ z.zstream.zfree = Z_NULL;
+ z.zstream.opaque = Z_NULL;
+
+ break;
+
+#ifdef HAVE_BZLIB_H
+ case PGP_C_BZIP2:
+ (void) memset(&bz, 0x0, sizeof(bz));
+
+ bz.region = region;
+ bz.offset = 0;
+ bz.type = type;
+
+ bz.bzstream.next_in = NULL;
+ bz.bzstream.avail_in = 0;
+ bz.bzstream.next_out = bz.out;
+ bz.bzstream.bzalloc = NULL;
+ bz.bzstream.bzfree = NULL;
+ bz.bzstream.opaque = NULL;
+#endif
+
+ break;
+
+ default:
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_COMPRESS_ALG,
+ "Compression algorithm %d is not yet supported", type);
+ return 0;
+ }
+
+ switch (type) {
+ case PGP_C_ZIP:
+ /* LINTED */ /* this is a lint problem in zlib.h header */
+ ret = (int)inflateInit2(&z.zstream, -15);
+ break;
+
+ case PGP_C_ZLIB:
+ /* LINTED */ /* this is a lint problem in zlib.h header */
+ ret = (int)inflateInit(&z.zstream);
+ break;
+
+#ifdef HAVE_BZLIB_H
+ case PGP_C_BZIP2:
+ ret = BZ2_bzDecompressInit(&bz.bzstream, 1, 0);
+ break;
+#endif
+
+ default:
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_COMPRESS_ALG,
+ "Compression algorithm %d is not yet supported", type);
+ return 0;
+ }
+
+ switch (type) {
+ case PGP_C_ZIP:
+ case PGP_C_ZLIB:
+ if (ret != Z_OK) {
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_P_DECOMPRESSION_ERROR,
+"Cannot initialise ZIP or ZLIB stream for decompression: error=%d", ret);
+ return 0;
+ }
+ pgp_reader_push(stream, zlib_compressed_data_reader,
+ NULL, &z);
+ break;
+
+#ifdef HAVE_BZLIB_H
+ case PGP_C_BZIP2:
+ if (ret != BZ_OK) {
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_P_DECOMPRESSION_ERROR,
+"Cannot initialise BZIP2 stream for decompression: error=%d", ret);
+ return 0;
+ }
+ pgp_reader_push(stream, bzip2_compressed_data_reader,
+ NULL, &bz);
+ break;
+#endif
+
+ default:
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_COMPRESS_ALG,
+ "Compression algorithm %d is not yet supported", type);
+ return 0;
+ }
+
+ ret = pgp_parse(stream, !printerrors);
+
+ pgp_reader_pop(stream);
+
+ return ret;
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Writes Compressed packet
+\param data Data to write out
+\param len Length of data
+\param output Write settings
+\return 1 if OK; else 0
+*/
+
+unsigned
+pgp_writez(pgp_output_t *out, const uint8_t *data, const unsigned len)
+{
+ compress_t *zip;
+ size_t sz_in;
+ size_t sz_out;
+ int ret;
+ int r = 0;
+
+ /* compress the data */
+ const int level = Z_DEFAULT_COMPRESSION; /* \todo allow varying
+ * levels */
+
+ if ((zip = calloc(1, sizeof(*zip))) == NULL) {
+ (void) fprintf(stderr, "pgp_writez: bad alloc\n");
+ return 0;
+ }
+ zip->stream.zalloc = Z_NULL;
+ zip->stream.zfree = Z_NULL;
+ zip->stream.opaque = NULL;
+
+ /* all other fields set to zero by use of calloc */
+
+ /* LINTED */ /* this is a lint problem in zlib.h header */
+ if ((int)deflateInit(&zip->stream, level) != Z_OK) {
+ (void) fprintf(stderr, "pgp_writez: can't initialise\n");
+ return 0;
+ }
+ /* do necessary transformation */
+ /* copy input to maintain const'ness of src */
+ if (zip->src != NULL || zip->dst != NULL) {
+ (void) fprintf(stderr, "pgp_writez: non-null streams\n");
+ return 0;
+ }
+
+ sz_in = len * sizeof(uint8_t);
+ sz_out = ((101 * sz_in) / 100) + 12; /* from zlib webpage */
+ if ((zip->src = calloc(1, sz_in)) == NULL) {
+ free(zip);
+ (void) fprintf(stderr, "pgp_writez: bad alloc2\n");
+ return 0;
+ }
+ if ((zip->dst = calloc(1, sz_out)) == NULL) {
+ free(zip->src);
+ free(zip);
+ (void) fprintf(stderr, "pgp_writez: bad alloc3\n");
+ return 0;
+ }
+ (void) memcpy(zip->src, data, len);
+
+ /* setup stream */
+ zip->stream.next_in = zip->src;
+ zip->stream.avail_in = (unsigned)sz_in;
+ zip->stream.total_in = 0;
+
+ zip->stream.next_out = zip->dst;
+ zip->stream.avail_out = (unsigned)sz_out;
+ zip->stream.total_out = 0;
+
+ do {
+ r = deflate(&zip->stream, Z_FINISH);
+ } while (r != Z_STREAM_END);
+
+ /* write it out */
+ ret = pgp_write_ptag(out, PGP_PTAG_CT_COMPRESSED) &&
+ pgp_write_length(out, (unsigned)(zip->stream.total_out + 1))&&
+ pgp_write_scalar(out, PGP_C_ZLIB, 1) &&
+ pgp_write(out, zip->dst, (unsigned)zip->stream.total_out);
+
+ free(zip->src);
+ free(zip->dst);
+ free(zip);
+ return ret;
+}
diff --git a/libs/netpgp/src/lib/config-original-as-configured-for-ubuntu-16.04-64bit.h b/libs/netpgp/src/lib/config-original-as-configured-for-ubuntu-16.04-64bit.h
new file mode 100644
index 00000000..5163cff2
--- /dev/null
+++ b/libs/netpgp/src/lib/config-original-as-configured-for-ubuntu-16.04-64bit.h
@@ -0,0 +1,187 @@
+/* src/lib/config.h. Generated from config.h.in by configure. */
+/* src/lib/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_BZLIB_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_COMMONCRYPTO_COMMONDIGEST_H */
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_DIRECT_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_DMALLOC_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_AES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_BN_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_CAMELLIA_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_CAST_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_DES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_DSA_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_OPENSSL_IDEA_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_MD5_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_RAND_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_SHA_H 1
+
+/* Define to 1 if the system has the type `SHA256_CTX'. */
+#define HAVE_SHA256_CTX 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_CDEFS_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "netpgp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "Alistair Crooks c0596823"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "netpgp"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "netpgp 20140220"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "netpgp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "20140220"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "20140220"
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from ,
+ , or is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from ,
+ , or is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from ,
+ , or is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to `unsigned int' if does not define. */
+/* #undef size_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
diff --git a/libs/netpgp/src/lib/config.h b/libs/netpgp/src/lib/config.h
new file mode 100644
index 00000000..f8bde141
--- /dev/null
+++ b/libs/netpgp/src/lib/config.h
@@ -0,0 +1,187 @@
+/* src/lib/config.h. Generated from config.h.in by configure. */
+/* src/lib/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the header file. */
+/*#undef HAVE_BZLIB_H 1*/ /* EDIT BY MR */
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_COMMONCRYPTO_COMMONDIGEST_H */
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_DIRECT_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_DMALLOC_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_AES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_BN_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_CAMELLIA_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_CAST_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_DES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_DSA_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_OPENSSL_IDEA_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_MD5_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_RAND_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_OPENSSL_SHA_H 1
+
+/* Define to 1 if the system has the type `SHA256_CTX'. */
+#define HAVE_SHA256_CTX 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_CDEFS_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "netpgp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "Alistair Crooks c0596823"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "netpgp"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "netpgp 20140220"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "netpgp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "20140220"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "20140220"
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from ,
+ , or is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from ,
+ , or is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from ,
+ , or is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to `unsigned int' if does not define. */
+/* #undef size_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
diff --git a/libs/netpgp/src/lib/create.c b/libs/netpgp/src/lib/create.c
new file mode 100644
index 00000000..00d85fe5
--- /dev/null
+++ b/libs/netpgp/src/lib/create.c
@@ -0,0 +1,1303 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: create.c,v 1.38 2010/11/15 08:03:39 agc Exp $");
+#endif
+
+#include
+#include
+#include
+
+#ifdef HAVE_FCNTL_H
+#include
+#endif
+
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_CAST_H
+#include
+#endif
+
+#include "create.h"
+#include "keyring.h"
+#include "packet.h"
+#include "signature.h"
+#include "writer.h"
+#include "readerwriter.h"
+#include "memory.h"
+#include "netpgpdefs.h"
+#include "netpgpdigest.h"
+
+/**
+ * \ingroup Core_Create
+ * \param length
+ * \param type
+ * \param output
+ * \return 1 if OK, otherwise 0
+ */
+
+unsigned
+pgp_write_ss_header(pgp_output_t *output,
+ unsigned length,
+ pgp_content_enum type)
+{
+ return pgp_write_length(output, length) &&
+ pgp_write_scalar(output, (unsigned)(type -
+ (unsigned)PGP_PTAG_SIG_SUBPKT_BASE), 1);
+}
+
+/*
+ * XXX: the general idea of _fast_ is that it doesn't copy stuff the safe
+ * (i.e. non _fast_) version will, and so will also need to be freed.
+ */
+
+/**
+ * \ingroup Core_Create
+ *
+ * pgp_fast_create_userid() sets id->userid to the given userid.
+ * This is fast because it is only copying a char*. However, if userid
+ * is changed or freed in the future, this could have injurious results.
+ * \param id
+ * \param userid
+ */
+
+void
+pgp_fast_create_userid(uint8_t **id, uint8_t *userid)
+{
+ *id = userid;
+}
+
+/**
+ * \ingroup Core_WritePackets
+ * \brief Writes a User Id packet
+ * \param id
+ * \param output
+ * \return 1 if OK, otherwise 0
+ */
+unsigned
+pgp_write_struct_userid(pgp_output_t *output, const uint8_t *id)
+{
+ return pgp_write_ptag(output, PGP_PTAG_CT_USER_ID) &&
+ pgp_write_length(output, (unsigned)strlen((const char *) id)) &&
+ pgp_write(output, id, (unsigned)strlen((const char *) id));
+}
+
+/**
+ * \ingroup Core_WritePackets
+ * \brief Write a User Id packet.
+ * \param userid
+ * \param output
+ *
+ * \return return value from pgp_write_struct_userid()
+ */
+unsigned
+pgp_write_userid(const uint8_t *userid, pgp_output_t *output)
+{
+ return pgp_write_struct_userid(output, userid);
+}
+
+/**
+\ingroup Core_MPI
+*/
+static unsigned
+mpi_length(const BIGNUM *bn)
+{
+ return (unsigned)(2 + (BN_num_bits(bn) + 7) / 8);
+}
+
+static unsigned
+pubkey_length(const pgp_pubkey_t *key)
+{
+ switch (key->alg) {
+ case PGP_PKA_DSA:
+ return mpi_length(key->key.dsa.p) + mpi_length(key->key.dsa.q) +
+ mpi_length(key->key.dsa.g) + mpi_length(key->key.dsa.y);
+
+ case PGP_PKA_RSA:
+ return mpi_length(key->key.rsa.n) + mpi_length(key->key.rsa.e);
+
+ default:
+ (void) fprintf(stderr,
+ "pubkey_length: unknown key algorithm\n");
+ }
+ return 0;
+}
+
+static unsigned
+seckey_length(const pgp_seckey_t *key)
+{
+ int len;
+
+ len = 0;
+ switch (key->pubkey.alg) {
+ case PGP_PKA_DSA:
+ return (unsigned)(mpi_length(key->key.dsa.x) + pubkey_length(&key->pubkey));
+ case PGP_PKA_RSA:
+ len = mpi_length(key->key.rsa.d) + mpi_length(key->key.rsa.p) +
+ mpi_length(key->key.rsa.q) + mpi_length(key->key.rsa.u);
+
+ return (unsigned)(len + pubkey_length(&key->pubkey));
+ default:
+ (void) fprintf(stderr,
+ "seckey_length: unknown key algorithm\n");
+ }
+ return 0;
+}
+
+/**
+ * \ingroup Core_Create
+ * \param key
+ * \param t
+ * \param n
+ * \param e
+*/
+void
+pgp_fast_create_rsa_pubkey(pgp_pubkey_t *key, time_t t,
+ BIGNUM *n, BIGNUM *e)
+{
+ key->version = PGP_V4;
+ key->birthtime = t;
+ key->alg = PGP_PKA_RSA;
+ key->key.rsa.n = n;
+ key->key.rsa.e = e;
+}
+
+/*
+ * Note that we support v3 keys here because they're needed for for
+ * verification - the writer doesn't allow them, though
+ */
+static unsigned
+write_pubkey_body(const pgp_pubkey_t *key, pgp_output_t *output)
+{
+ if (!(pgp_write_scalar(output, (unsigned)key->version, 1) &&
+ pgp_write_scalar(output, (unsigned)key->birthtime, 4))) {
+ return 0;
+ }
+
+ if (key->version != 4 &&
+ !pgp_write_scalar(output, key->days_valid, 2)) {
+ return 0;
+ }
+
+ if (!pgp_write_scalar(output, (unsigned)key->alg, 1)) {
+ return 0;
+ }
+
+ switch (key->alg) {
+ case PGP_PKA_DSA:
+ return pgp_write_mpi(output, key->key.dsa.p) &&
+ pgp_write_mpi(output, key->key.dsa.q) &&
+ pgp_write_mpi(output, key->key.dsa.g) &&
+ pgp_write_mpi(output, key->key.dsa.y);
+
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ return pgp_write_mpi(output, key->key.rsa.n) &&
+ pgp_write_mpi(output, key->key.rsa.e);
+
+ case PGP_PKA_ELGAMAL:
+ return pgp_write_mpi(output, key->key.elgamal.p) &&
+ pgp_write_mpi(output, key->key.elgamal.g) &&
+ pgp_write_mpi(output, key->key.elgamal.y);
+
+ default:
+ (void) fprintf(stderr,
+ "write_pubkey_body: bad algorithm\n");
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Note that we support v3 keys here because they're needed for
+ * verification.
+ */
+static unsigned
+write_seckey_body(const pgp_seckey_t *key,
+ const uint8_t *passphrase,
+ const size_t pplen,
+ pgp_output_t *output)
+{
+ /* RFC4880 Section 5.5.3 Secret-Key Packet Formats */
+
+ pgp_crypt_t crypted;
+ pgp_hash_t hash;
+ unsigned done = 0;
+ unsigned i = 0;
+ uint8_t *hashed;
+ uint8_t sesskey[CAST_KEY_LENGTH];
+
+ if (!write_pubkey_body(&key->pubkey, output)) {
+ return 0;
+ }
+ if (key->s2k_usage != PGP_S2KU_ENCRYPTED_AND_HASHED) {
+ (void) fprintf(stderr, "write_seckey_body: s2k usage\n");
+ return 0;
+ }
+ if (!pgp_write_scalar(output, (unsigned)key->s2k_usage, 1)) {
+ return 0;
+ }
+
+ if (key->alg != PGP_SA_CAST5) {
+ (void) fprintf(stderr, "write_seckey_body: algorithm\n");
+ return 0;
+ }
+ if (!pgp_write_scalar(output, (unsigned)key->alg, 1)) {
+ return 0;
+ }
+
+ if (key->s2k_specifier != PGP_S2KS_SIMPLE &&
+ key->s2k_specifier != PGP_S2KS_SALTED) {
+ /* = 1 \todo could also be iterated-and-salted */
+ (void) fprintf(stderr, "write_seckey_body: s2k spec\n");
+ return 0;
+ }
+ if (!pgp_write_scalar(output, (unsigned)key->s2k_specifier, 1)) {
+ return 0;
+ }
+ if (!pgp_write_scalar(output, (unsigned)key->hash_alg, 1)) {
+ return 0;
+ }
+
+ switch (key->s2k_specifier) {
+ case PGP_S2KS_SIMPLE:
+ /* nothing more to do */
+ break;
+
+ case PGP_S2KS_SALTED:
+ /* 8-octet salt value */
+ pgp_random(__UNCONST(&key->salt[0]), PGP_SALT_SIZE);
+ if (!pgp_write(output, key->salt, PGP_SALT_SIZE)) {
+ return 0;
+ }
+ break;
+
+ /*
+ * \todo case PGP_S2KS_ITERATED_AND_SALTED: // 8-octet salt
+ * value // 1-octet count break;
+ */
+
+ default:
+ (void) fprintf(stderr,
+ "invalid/unsupported s2k specifier %d\n",
+ key->s2k_specifier);
+ return 0;
+ }
+
+ if (!pgp_write(output, &key->iv[0], pgp_block_size(key->alg))) {
+ return 0;
+ }
+
+ /*
+ * create the session key for encrypting the algorithm-specific
+ * fields
+ */
+
+ switch (key->s2k_specifier) {
+ case PGP_S2KS_SIMPLE:
+ case PGP_S2KS_SALTED:
+ /* RFC4880: section 3.7.1.1 and 3.7.1.2 */
+
+ for (done = 0, i = 0; done < CAST_KEY_LENGTH; i++) {
+ unsigned hashsize;
+ unsigned j;
+ unsigned needed;
+ unsigned size;
+ uint8_t zero = 0;
+
+ /* Hard-coded SHA1 for session key */
+ pgp_hash_any(&hash, PGP_HASH_SHA1);
+ hashsize = pgp_hash_size(key->hash_alg);
+ needed = CAST_KEY_LENGTH - done;
+ size = MIN(needed, hashsize);
+ if ((hashed = calloc(1, hashsize)) == NULL) {
+ (void) fprintf(stderr, "write_seckey_body: bad alloc\n");
+ return 0;
+ }
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr, "write_seckey_body: bad alloc\n");
+ return 0;
+ }
+
+ /* preload if iterating */
+ for (j = 0; j < i; j++) {
+ /*
+ * Coverity shows a DEADCODE error on this
+ * line. This is expected since the hardcoded
+ * use of SHA1 and CAST5 means that it will
+ * not used. This will change however when
+ * other algorithms are supported.
+ */
+ hash.add(&hash, &zero, 1);
+ }
+
+ if (key->s2k_specifier == PGP_S2KS_SALTED) {
+ hash.add(&hash, key->salt, PGP_SALT_SIZE);
+ }
+ hash.add(&hash, passphrase, (unsigned)pplen);
+ hash.finish(&hash, hashed);
+
+ /*
+ * if more in hash than is needed by session key, use
+ * the leftmost octets
+ */
+ (void) memcpy(&sesskey[i * hashsize],
+ hashed, (unsigned)size);
+ done += (unsigned)size;
+ if (done > CAST_KEY_LENGTH) {
+ (void) fprintf(stderr,
+ "write_seckey_body: short add\n");
+ return 0;
+ }
+ }
+
+ break;
+
+ /*
+ * \todo case PGP_S2KS_ITERATED_AND_SALTED: * 8-octet salt
+ * value * 1-octet count break;
+ */
+
+ default:
+ (void) fprintf(stderr,
+ "invalid/unsupported s2k specifier %d\n",
+ key->s2k_specifier);
+ return 0;
+ }
+
+ /* use this session key to encrypt */
+
+ pgp_crypt_any(&crypted, key->alg);
+ crypted.set_iv(&crypted, key->iv);
+ crypted.set_crypt_key(&crypted, sesskey);
+ pgp_encrypt_init(&crypted);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "writing: iv=", key->iv, pgp_block_size(key->alg));
+ hexdump(stderr, "key= ", sesskey, CAST_KEY_LENGTH);
+ (void) fprintf(stderr, "\nturning encryption on...\n");
+ }
+ pgp_push_enc_crypt(output, &crypted);
+
+ switch (key->pubkey.alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (!pgp_write_mpi(output, key->key.rsa.d) ||
+ !pgp_write_mpi(output, key->key.rsa.p) ||
+ !pgp_write_mpi(output, key->key.rsa.q) ||
+ !pgp_write_mpi(output, key->key.rsa.u)) {
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr,
+ "4 x mpi not written - problem\n");
+ }
+ return 0;
+ }
+ break;
+ case PGP_PKA_DSA:
+ return pgp_write_mpi(output, key->key.dsa.x);
+ case PGP_PKA_ELGAMAL:
+ return pgp_write_mpi(output, key->key.elgamal.x);
+ default:
+ return 0;
+ }
+
+ if (!pgp_write(output, key->checkhash, PGP_CHECKHASH_SIZE)) {
+ return 0;
+ }
+
+ pgp_writer_pop(output);
+
+ return 1;
+}
+
+/**
+ * \ingroup Core_WritePackets
+ * \brief Writes a Public Key packet
+ * \param key
+ * \param output
+ * \return 1 if OK, otherwise 0
+ */
+static unsigned
+write_struct_pubkey(pgp_output_t *output, const pgp_pubkey_t *key)
+{
+ return pgp_write_ptag(output, PGP_PTAG_CT_PUBLIC_KEY) &&
+ pgp_write_length(output, 1 + 4 + 1 + pubkey_length(key)) &&
+ write_pubkey_body(key, output);
+}
+
+
+/**
+ \ingroup HighLevel_KeyWrite
+
+ \brief Writes a transferable PGP public key to the given output stream.
+
+ \param keydata Key to be written
+ \param armoured Flag is set for armoured output
+ \param output Output stream
+
+*/
+
+unsigned
+pgp_write_xfer_pubkey(pgp_output_t *output,
+ const pgp_key_t *key,
+ const unsigned armoured)
+{
+ unsigned i, j;
+
+ if (armoured) {
+ pgp_writer_push_armoured(output, PGP_PGP_PUBLIC_KEY_BLOCK);
+ }
+ /* public key */
+ if (!write_struct_pubkey(output, &key->key.pubkey)) {
+ return 0;
+ }
+
+ /* TODO: revocation signatures go here */
+
+ /* user ids and corresponding signatures */
+ for (i = 0; i < key->uidc; i++) {
+ if (!pgp_write_struct_userid(output, key->uids[i])) {
+ return 0;
+ }
+ for (j = 0; j < key->packetc; j++) {
+ if (!pgp_write(output, key->packets[j].raw, (unsigned)key->packets[j].length)) {
+ return 0;
+ }
+ }
+ }
+
+ /* TODO: user attributes and corresponding signatures */
+
+ /*
+ * subkey packets and corresponding signatures and optional
+ * revocation
+ */
+
+ if (armoured) {
+ pgp_writer_info_finalise(&output->errors, &output->writer);
+ pgp_writer_pop(output);
+ }
+ return 1;
+}
+
+/**
+ \ingroup HighLevel_KeyWrite
+
+ \brief Writes a transferable PGP secret key to the given output stream.
+
+ \param keydata Key to be written
+ \param passphrase
+ \param pplen
+ \param armoured Flag is set for armoured output
+ \param output Output stream
+
+*/
+
+unsigned
+pgp_write_xfer_seckey(pgp_output_t *output,
+ const pgp_key_t *key,
+ const uint8_t *passphrase,
+ const size_t pplen,
+ unsigned armoured)
+{
+ unsigned i, j;
+
+ if (armoured) {
+ pgp_writer_push_armoured(output, PGP_PGP_PRIVATE_KEY_BLOCK);
+ }
+ /* public key */
+ if (!pgp_write_struct_seckey(&key->key.seckey, passphrase,
+ pplen, output)) {
+ return 0;
+ }
+
+ /* TODO: revocation signatures go here */
+
+ /* user ids and corresponding signatures */
+ for (i = 0; i < key->uidc; i++) {
+ if (!pgp_write_struct_userid(output, key->uids[i])) {
+ return 0;
+ }
+ for (j = 0; j < key->packetc; j++) {
+ if (!pgp_write(output, key->packets[j].raw, (unsigned)key->packets[j].length)) {
+ return 0;
+ }
+ }
+ }
+
+ /* TODO: user attributes and corresponding signatures */
+
+ /*
+ * subkey packets and corresponding signatures and optional
+ * revocation
+ */
+
+ if (armoured) {
+ pgp_writer_info_finalise(&output->errors, &output->writer);
+ pgp_writer_pop(output);
+ }
+ return 1;
+}
+
+/**
+ * \ingroup Core_WritePackets
+ * \brief Writes one RSA public key packet.
+ * \param t Creation time
+ * \param n RSA public modulus
+ * \param e RSA public encryption exponent
+ * \param output Writer settings
+ *
+ * \return 1 if OK, otherwise 0
+ */
+
+unsigned
+pgp_write_rsa_pubkey(time_t t, const BIGNUM *n,
+ const BIGNUM *e,
+ pgp_output_t *output)
+{
+ pgp_pubkey_t key;
+
+ pgp_fast_create_rsa_pubkey(&key, t, __UNCONST(n), __UNCONST(e));
+ return write_struct_pubkey(output, &key);
+}
+
+/**
+ * \ingroup Core_Create
+ * \param out
+ * \param key
+ * \param make_packet
+ */
+
+void
+pgp_build_pubkey(pgp_memory_t *out, const pgp_pubkey_t *key,
+ unsigned make_packet)
+{
+ pgp_output_t *output;
+
+ output = pgp_output_new();
+ pgp_memory_init(out, 128);
+ pgp_writer_set_memory(output, out);
+ write_pubkey_body(key, output);
+ if (make_packet) {
+ pgp_memory_make_packet(out, PGP_PTAG_CT_PUBLIC_KEY);
+ }
+ pgp_output_delete(output);
+}
+
+/**
+ * \ingroup Core_Create
+ *
+ * Create an RSA secret key structure. If a parameter is marked as
+ * [OPTIONAL], then it can be omitted and will be calculated from
+ * other params - or, in the case of e, will default to 0x10001.
+ *
+ * Parameters are _not_ copied, so will be freed if the structure is
+ * freed.
+ *
+ * \param key The key structure to be initialised.
+ * \param t
+ * \param d The RSA parameter d (=e^-1 mod (p-1)(q-1)) [OPTIONAL]
+ * \param p The RSA parameter p
+ * \param q The RSA parameter q (q > p)
+ * \param u The RSA parameter u (=p^-1 mod q) [OPTIONAL]
+ * \param n The RSA public parameter n (=p*q) [OPTIONAL]
+ * \param e The RSA public parameter e */
+
+void
+pgp_fast_create_rsa_seckey(pgp_seckey_t *key, time_t t,
+ BIGNUM *d, BIGNUM *p, BIGNUM *q, BIGNUM *u,
+ BIGNUM *n, BIGNUM *e)
+{
+ pgp_fast_create_rsa_pubkey(&key->pubkey, t, n, e);
+
+ /* XXX: calculate optionals */
+ key->key.rsa.d = d;
+ key->key.rsa.p = p;
+ key->key.rsa.q = q;
+ key->key.rsa.u = u;
+
+ key->s2k_usage = PGP_S2KU_NONE;
+
+ /* XXX: sanity check and add errors... */
+}
+
+/**
+ * \ingroup Core_WritePackets
+ * \brief Writes a Secret Key packet.
+ * \param key The secret key
+ * \param passphrase The passphrase
+ * \param pplen Length of passphrase
+ * \param output
+ * \return 1 if OK; else 0
+ */
+unsigned
+pgp_write_struct_seckey(const pgp_seckey_t *key,
+ const uint8_t *passphrase,
+ const size_t pplen,
+ pgp_output_t *output)
+{
+ int length = 0;
+
+ if (key->pubkey.version != 4) {
+ (void) fprintf(stderr,
+ "pgp_write_struct_seckey: public key version\n");
+ return 0;
+ }
+
+ /* Ref: RFC4880 Section 5.5.3 */
+
+ /* pubkey, excluding MPIs */
+ length += 1 + 4 + 1 + 1;
+
+ /* s2k usage */
+ length += 1;
+
+ switch (key->s2k_usage) {
+ case PGP_S2KU_NONE:
+ /* nothing to add */
+ break;
+
+ case PGP_S2KU_ENCRYPTED_AND_HASHED: /* 254 */
+ case PGP_S2KU_ENCRYPTED: /* 255 */
+
+ /* Ref: RFC4880 Section 3.7 */
+ length += 1; /* s2k_specifier */
+
+ switch (key->s2k_specifier) {
+ case PGP_S2KS_SIMPLE:
+ length += 1; /* hash algorithm */
+ break;
+
+ case PGP_S2KS_SALTED:
+ length += 1 + 8; /* hash algorithm + salt */
+ break;
+
+ case PGP_S2KS_ITERATED_AND_SALTED:
+ length += 1 + 8 + 1; /* hash algorithm, salt +
+ * count */
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_write_struct_seckey: s2k spec\n");
+ return 0;
+ }
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_write_struct_seckey: s2k usage\n");
+ return 0;
+ }
+
+ /* IV */
+ if (key->s2k_usage) {
+ length += pgp_block_size(key->alg);
+ }
+ /* checksum or hash */
+ switch (key->s2k_usage) {
+ case PGP_S2KU_NONE:
+ case PGP_S2KU_ENCRYPTED:
+ length += 2;
+ break;
+
+ case PGP_S2KU_ENCRYPTED_AND_HASHED:
+ length += PGP_CHECKHASH_SIZE;
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_write_struct_seckey: s2k cksum usage\n");
+ return 0;
+ }
+
+ /* secret key and public key MPIs */
+ length += (unsigned)seckey_length(key);
+
+ return pgp_write_ptag(output, PGP_PTAG_CT_SECRET_KEY) &&
+ /* pgp_write_length(output,1+4+1+1+seckey_length(key)+2) && */
+ pgp_write_length(output, (unsigned)length) &&
+ write_seckey_body(key, passphrase, pplen, output);
+}
+
+/**
+ * \ingroup Core_Create
+ *
+ * \brief Create a new pgp_output_t structure.
+ *
+ * \return the new structure.
+ * \note It is the responsiblity of the caller to call pgp_output_delete().
+ * \sa pgp_output_delete()
+ */
+pgp_output_t *
+pgp_output_new(void)
+{
+ return calloc(1, sizeof(pgp_output_t));
+}
+
+/**
+ * \ingroup Core_Create
+ * \brief Delete an pgp_output_t strucut and associated resources.
+ *
+ * Delete an pgp_output_t structure. If a writer is active, then
+ * that is also deleted.
+ *
+ * \param info the structure to be deleted.
+ */
+void
+pgp_output_delete(pgp_output_t *output)
+{
+ pgp_writer_info_delete(&output->writer);
+ free(output);
+}
+
+/**
+ \ingroup Core_Create
+ \brief Calculate the checksum for a session key
+ \param sesskey Session Key to use
+ \param cs Checksum to be written
+ \return 1 if OK; else 0
+*/
+unsigned
+pgp_calc_sesskey_checksum(pgp_pk_sesskey_t *sesskey, uint8_t cs[2])
+{
+ uint32_t checksum = 0;
+ unsigned i;
+
+ if (!pgp_is_sa_supported(sesskey->symm_alg)) {
+ return 0;
+ }
+
+ for (i = 0; i < pgp_key_size(sesskey->symm_alg); i++) {
+ checksum += sesskey->key[i];
+ }
+ checksum = checksum % 65536;
+
+ cs[0] = (uint8_t)((checksum >> 8) & 0xff);
+ cs[1] = (uint8_t)(checksum & 0xff);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "nm buf checksum:", cs, 2);
+ }
+ return 1;
+}
+
+static unsigned
+create_unencoded_m_buf(pgp_pk_sesskey_t *sesskey, pgp_crypt_t *cipherinfo, uint8_t *m_buf)
+{
+ unsigned i;
+
+ /* m_buf is the buffer which will be encoded in PKCS#1 block
+ * encoding to form the "m" value used in the Public Key
+ * Encrypted Session Key Packet as defined in RFC Section 5.1
+ * "Public-Key Encrypted Session Key Packet"
+ */
+ m_buf[0] = sesskey->symm_alg;
+ for (i = 0; i < cipherinfo->keysize ; i++) {
+ /* XXX - Flexelint - Warning 679: Suspicious Truncation in arithmetic expression combining with pointer */
+ m_buf[1 + i] = sesskey->key[i];
+ }
+
+ return pgp_calc_sesskey_checksum(sesskey,
+ m_buf + 1 + cipherinfo->keysize);
+}
+
+/**
+\ingroup Core_Create
+\brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
+\param M
+\param mLen
+\param pubkey
+\param EM
+\return 1 if OK; else 0
+*/
+unsigned
+encode_m_buf(const uint8_t *M, size_t mLen, const pgp_pubkey_t * pubkey,
+ uint8_t *EM)
+{
+ unsigned k;
+ unsigned i;
+
+ /* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
+ switch (pubkey->alg) {
+ case PGP_PKA_RSA:
+ k = (unsigned)BN_num_bytes(pubkey->key.rsa.n);
+ if (mLen > k - 11) {
+ (void) fprintf(stderr, "encode_m_buf: message too long\n");
+ return 0;
+ }
+ break;
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ k = (unsigned)BN_num_bytes(pubkey->key.elgamal.p);
+ if (mLen > k - 11) {
+ (void) fprintf(stderr, "encode_m_buf: message too long\n");
+ return 0;
+ }
+ break;
+ default:
+ (void) fprintf(stderr, "encode_m_buf: pubkey algorithm\n");
+ return 0;
+ }
+ /* these two bytes defined by RFC */
+ EM[0] = 0x00;
+ EM[1] = 0x02;
+ /* add non-zero random bytes of length k - mLen -3 */
+ for (i = 2; i < (k - mLen) - 1; ++i) {
+ do {
+ pgp_random(EM + i, 1);
+ } while (EM[i] == 0);
+ }
+ if (i < 8 + 2) {
+ (void) fprintf(stderr, "encode_m_buf: bad i len\n");
+ return 0;
+ }
+ EM[i++] = 0;
+ (void) memcpy(EM + i, M, mLen);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "Encoded Message:", EM, mLen);
+ }
+ return 1;
+}
+
+/**
+ \ingroup Core_Create
+\brief Creates an pgp_pk_sesskey_t struct from keydata
+\param key Keydata to use
+\return pgp_pk_sesskey_t struct
+\note It is the caller's responsiblity to free the returned pointer
+\note Currently hard-coded to use CAST5
+\note Currently hard-coded to use RSA
+*/
+pgp_pk_sesskey_t *
+pgp_create_pk_sesskey(const pgp_key_t *key, const char *ciphername)
+{
+ /*
+ * Creates a random session key and encrypts it for the given key
+ *
+ * Encryption used is PK,
+ * can be any, we're hardcoding RSA for now
+ */
+
+ const pgp_pubkey_t *pubkey;
+ pgp_pk_sesskey_t *sesskey;
+ pgp_symm_alg_t cipher;
+ const uint8_t *id;
+ pgp_crypt_t cipherinfo;
+ uint8_t *unencoded_m_buf;
+ uint8_t *encoded_m_buf;
+ size_t sz_encoded_m_buf;
+
+ if (memcmp(key->encid, "\0\0\0\0\0\0\0\0", 8) == 0) {
+ pubkey = pgp_get_pubkey(key);
+ id = key->sigid;
+ } else {
+ pubkey = &key->enckey;
+ id = key->encid;
+ }
+ /* allocate unencoded_m_buf here */
+ (void) memset(&cipherinfo, 0x0, sizeof(cipherinfo));
+ pgp_crypt_any(&cipherinfo,
+ cipher = pgp_str_to_cipher((ciphername) ? ciphername : "cast5"));
+ unencoded_m_buf = calloc(1, cipherinfo.keysize + 1 + 2);
+ if (unencoded_m_buf == NULL) {
+ (void) fprintf(stderr,
+ "pgp_create_pk_sesskey: can't allocate\n");
+ return NULL;
+ }
+ switch(pubkey->alg) {
+ case PGP_PKA_RSA:
+ sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
+ break;
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ sz_encoded_m_buf = BN_num_bytes(pubkey->key.elgamal.p);
+ break;
+ default:
+ sz_encoded_m_buf = 0;
+ break;
+ }
+ if ((encoded_m_buf = calloc(1, sz_encoded_m_buf)) == NULL) {
+ (void) fprintf(stderr,
+ "pgp_create_pk_sesskey: can't allocate\n");
+ free(unencoded_m_buf);
+ return NULL;
+ }
+ if ((sesskey = calloc(1, sizeof(*sesskey))) == NULL) {
+ (void) fprintf(stderr,
+ "pgp_create_pk_sesskey: can't allocate\n");
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ return NULL;
+ }
+ if (key->type != PGP_PTAG_CT_PUBLIC_KEY) {
+ (void) fprintf(stderr,
+ "pgp_create_pk_sesskey: bad type\n");
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ free(sesskey);
+ return NULL;
+ }
+ sesskey->version = PGP_PKSK_V3;
+ (void) memcpy(sesskey->key_id, id, sizeof(sesskey->key_id));
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "Encrypting for keyid", id, sizeof(sesskey->key_id));
+ }
+ switch (pubkey->alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ break;
+ default:
+ (void) fprintf(stderr,
+ "pgp_create_pk_sesskey: bad pubkey algorithm\n");
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ free(sesskey);
+ return NULL;
+ }
+ sesskey->alg = pubkey->alg;
+
+ sesskey->symm_alg = cipher;
+ pgp_random(sesskey->key, cipherinfo.keysize);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sesskey created", sesskey->key,
+ cipherinfo.keysize + 1 + 2);
+ }
+ if (create_unencoded_m_buf(sesskey, &cipherinfo, &unencoded_m_buf[0]) == 0) {
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ free(sesskey);
+ return NULL;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "uuencoded m buf", unencoded_m_buf, cipherinfo.keysize + 1 + 2);
+ }
+ encode_m_buf(unencoded_m_buf, cipherinfo.keysize + 1 + 2, pubkey, encoded_m_buf);
+
+ /* and encrypt it */
+ switch (key->key.pubkey.alg) {
+ case PGP_PKA_RSA:
+ if (!pgp_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
+ &sesskey->params)) {
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ free(sesskey);
+ return NULL;
+ }
+ break;
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ if (!pgp_elgamal_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
+ &sesskey->params)) {
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ free(sesskey);
+ return NULL;
+ }
+ break;
+ default:
+ /* will not get here - for lint only */
+ break;
+ }
+ free(unencoded_m_buf);
+ free(encoded_m_buf);
+ return sesskey;
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Writes Public Key Session Key packet
+\param info Write settings
+\param pksk Public Key Session Key to write out
+\return 1 if OK; else 0
+*/
+unsigned
+pgp_write_pk_sesskey(pgp_output_t *output, pgp_pk_sesskey_t *pksk)
+{
+ /* XXX - Flexelint - Pointer parameter 'pksk' (line 1076) could be declared as pointing to const */
+ if (pksk == NULL) {
+ (void) fprintf(stderr,
+ "pgp_write_pk_sesskey: NULL pksk\n");
+ return 0;
+ }
+ switch (pksk->alg) {
+ case PGP_PKA_RSA:
+ return pgp_write_ptag(output, PGP_PTAG_CT_PK_SESSION_KEY) &&
+ pgp_write_length(output, (unsigned)(1 + 8 + 1 +
+ BN_num_bytes(pksk->params.rsa.encrypted_m) + 2)) &&
+ pgp_write_scalar(output, (unsigned)pksk->version, 1) &&
+ pgp_write(output, pksk->key_id, 8) &&
+ pgp_write_scalar(output, (unsigned)pksk->alg, 1) &&
+ pgp_write_mpi(output, pksk->params.rsa.encrypted_m)
+ /* ?? && pgp_write_scalar(output, 0, 2); */
+ ;
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ return pgp_write_ptag(output, PGP_PTAG_CT_PK_SESSION_KEY) &&
+ pgp_write_length(output, (unsigned)(1 + 8 + 1 +
+ BN_num_bytes(pksk->params.elgamal.g_to_k) + 2 +
+ BN_num_bytes(pksk->params.elgamal.encrypted_m) + 2)) &&
+ pgp_write_scalar(output, (unsigned)pksk->version, 1) &&
+ pgp_write(output, pksk->key_id, 8) &&
+ pgp_write_scalar(output, (unsigned)pksk->alg, 1) &&
+ pgp_write_mpi(output, pksk->params.elgamal.g_to_k) &&
+ pgp_write_mpi(output, pksk->params.elgamal.encrypted_m)
+ /* ?? && pgp_write_scalar(output, 0, 2); */
+ ;
+ default:
+ (void) fprintf(stderr,
+ "pgp_write_pk_sesskey: bad algorithm\n");
+ return 0;
+ }
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Writes MDC packet
+\param hashed Hash for MDC
+\param output Write settings
+\return 1 if OK; else 0
+*/
+
+unsigned
+pgp_write_mdc(pgp_output_t *output, const uint8_t *hashed)
+{
+ /* write it out */
+ return pgp_write_ptag(output, PGP_PTAG_CT_MDC) &&
+ pgp_write_length(output, PGP_SHA1_HASH_SIZE) &&
+ pgp_write(output, hashed, PGP_SHA1_HASH_SIZE);
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Writes Literal Data packet from buffer
+\param data Buffer to write out
+\param maxlen Max length of buffer
+\param type Literal Data Type
+\param output Write settings
+\return 1 if OK; else 0
+*/
+unsigned
+pgp_write_litdata(pgp_output_t *output,
+ const uint8_t *data,
+ const int maxlen,
+ const pgp_litdata_enum type)
+{
+ /*
+ * RFC4880 does not specify a meaning for filename or date.
+ * It is implementation-dependent.
+ * We will not implement them.
+ */
+ /* \todo do we need to check text data for line endings ? */
+ return pgp_write_ptag(output, PGP_PTAG_CT_LITDATA) &&
+ pgp_write_length(output, (unsigned)(1 + 1 + 4 + maxlen)) &&
+ pgp_write_scalar(output, (unsigned)type, 1) &&
+ pgp_write_scalar(output, 0, 1) &&
+ pgp_write_scalar(output, 0, 4) &&
+ pgp_write(output, data, (unsigned)maxlen);
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Writes Literal Data packet from contents of file
+\param filename Name of file to read from
+\param type Literal Data Type
+\param output Write settings
+\return 1 if OK; else 0
+*/
+
+unsigned
+pgp_fileread_litdata(const char *filename,
+ const pgp_litdata_enum type,
+ pgp_output_t *output)
+{
+ pgp_memory_t *mem;
+ unsigned ret;
+ int len;
+
+ mem = pgp_memory_new();
+ if (!pgp_mem_readfile(mem, filename)) {
+ (void) fprintf(stderr, "pgp_mem_readfile of '%s' failed\n", filename);
+ return 0;
+ }
+ len = (int)pgp_mem_len(mem);
+ ret = pgp_write_litdata(output, pgp_mem_data(mem), len, type);
+ pgp_memory_free(mem);
+ return ret;
+}
+
+/**
+ \ingroup HighLevel_General
+
+ \brief Writes contents of buffer into file
+
+ \param filename Filename to write to
+ \param buf Buffer to write to file
+ \param len Size of buffer
+ \param overwrite Flag to set whether to overwrite an existing file
+ \return 1 if OK; 0 if error
+*/
+
+int
+pgp_filewrite(const char *filename, const char *buf,
+ const size_t len, const unsigned overwrite)
+{
+ int flags;
+ int fd;
+
+ flags = O_WRONLY | O_CREAT;
+ if (overwrite) {
+ flags |= O_TRUNC;
+ } else {
+ flags |= O_EXCL;
+ }
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+ fd = open(filename, flags, 0600);
+ if (fd < 0) {
+ (void) fprintf(stderr, "can't open '%s'\n", filename);
+ return 0;
+ }
+ if (write(fd, buf, len) != (int)len) {
+ (void) close(fd);
+ return 0;
+ }
+
+ return (close(fd) == 0);
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Write Symmetrically Encrypted packet
+\param data Data to encrypt
+\param len Length of data
+\param output Write settings
+\return 1 if OK; else 0
+\note Hard-coded to use AES256
+*/
+unsigned
+pgp_write_symm_enc_data(const uint8_t *data,
+ const int len,
+ pgp_output_t * output)
+{
+ pgp_crypt_t crypt_info;
+ uint8_t *encrypted = (uint8_t *) NULL;
+ size_t encrypted_sz;
+ int done = 0;
+
+ /* \todo assume AES256 for now */
+ pgp_crypt_any(&crypt_info, PGP_SA_AES_256);
+ pgp_encrypt_init(&crypt_info);
+
+ encrypted_sz = (size_t)(len + crypt_info.blocksize + 2);
+ if ((encrypted = calloc(1, encrypted_sz)) == NULL) {
+ (void) fprintf(stderr, "can't allocate %" PRIsize "d\n",
+ encrypted_sz);
+ return 0;
+ }
+
+ done = (int)pgp_encrypt_se(&crypt_info, encrypted, data, (unsigned)len);
+ if (done != len) {
+ (void) fprintf(stderr,
+ "pgp_write_symm_enc_data: done != len\n");
+ return 0;
+ }
+
+ return pgp_write_ptag(output, PGP_PTAG_CT_SE_DATA) &&
+ pgp_write_length(output, (unsigned)(1 + encrypted_sz)) &&
+ pgp_write(output, data, (unsigned)len);
+}
+
+/**
+\ingroup Core_WritePackets
+\brief Write a One Pass Signature packet
+\param seckey Secret Key to use
+\param hash_alg Hash Algorithm to use
+\param sig_type Signature type
+\param output Write settings
+\return 1 if OK; else 0
+*/
+unsigned
+pgp_write_one_pass_sig(pgp_output_t *output,
+ const pgp_seckey_t *seckey,
+ const pgp_hash_alg_t hash_alg,
+ const pgp_sig_type_t sig_type)
+{
+ uint8_t keyid[PGP_KEY_ID_SIZE];
+
+ pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, PGP_HASH_SHA1); /* XXX - hardcoded */
+ return pgp_write_ptag(output, PGP_PTAG_CT_1_PASS_SIG) &&
+ pgp_write_length(output, 1 + 1 + 1 + 1 + 8 + 1) &&
+ pgp_write_scalar(output, 3, 1) /* version */ &&
+ pgp_write_scalar(output, (unsigned)sig_type, 1) &&
+ pgp_write_scalar(output, (unsigned)hash_alg, 1) &&
+ pgp_write_scalar(output, (unsigned)seckey->pubkey.alg, 1) &&
+ pgp_write(output, keyid, 8) &&
+ pgp_write_scalar(output, 1, 1);
+}
diff --git a/libs/netpgp/src/lib/create.h b/libs/netpgp/src/lib/create.h
new file mode 100644
index 00000000..a51b4fd6
--- /dev/null
+++ b/libs/netpgp/src/lib/create.h
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#ifndef CREATE_H_
+#define CREATE_H_
+
+#include "types.h"
+#include "packet.h"
+#include "crypto.h"
+#include "errors.h"
+#include "keyring.h"
+#include "writer.h"
+#include "memory.h"
+
+/**
+ * \ingroup Create
+ * This struct contains the required information about how to write this stream
+ */
+struct pgp_output_t {
+ pgp_writer_t writer;
+ pgp_error_t *errors; /* error stack */
+};
+
+pgp_output_t *pgp_output_new(void);
+void pgp_output_delete(pgp_output_t *);
+
+int pgp_filewrite(const char *, const char *, const size_t, const unsigned);
+
+void pgp_build_pubkey(pgp_memory_t *, const pgp_pubkey_t *, unsigned);
+
+unsigned pgp_calc_sesskey_checksum(pgp_pk_sesskey_t *, uint8_t *);
+unsigned pgp_write_struct_userid(pgp_output_t *, const uint8_t *);
+unsigned pgp_write_ss_header(pgp_output_t *, unsigned, pgp_content_enum);
+unsigned pgp_write_struct_seckey(const pgp_seckey_t *,
+ const uint8_t *,
+ const size_t,
+ pgp_output_t *);
+unsigned pgp_write_one_pass_sig(pgp_output_t *,
+ const pgp_seckey_t *,
+ const pgp_hash_alg_t,
+ const pgp_sig_type_t);
+unsigned pgp_write_litdata(pgp_output_t *,
+ const uint8_t *,
+ const int,
+ const pgp_litdata_enum);
+pgp_pk_sesskey_t *pgp_create_pk_sesskey(const pgp_key_t *, const char *);
+unsigned pgp_write_pk_sesskey(pgp_output_t *, pgp_pk_sesskey_t *);
+unsigned pgp_write_xfer_pubkey(pgp_output_t *,
+ const pgp_key_t *, const unsigned);
+unsigned pgp_write_xfer_seckey(pgp_output_t *,
+ const pgp_key_t *,
+ const uint8_t *,
+ const size_t,
+ const unsigned);
+
+void pgp_fast_create_userid(uint8_t **, uint8_t *);
+unsigned pgp_write_userid(const uint8_t *, pgp_output_t *);
+void pgp_fast_create_rsa_pubkey(pgp_pubkey_t *, time_t, BIGNUM *, BIGNUM *);
+unsigned pgp_write_rsa_pubkey(time_t, const BIGNUM *, const BIGNUM *,
+ pgp_output_t *);
+void pgp_fast_create_rsa_seckey(pgp_seckey_t *, time_t, BIGNUM *,
+ BIGNUM *, BIGNUM *, BIGNUM *,
+ BIGNUM *, BIGNUM *);
+unsigned encode_m_buf(const uint8_t *, size_t, const pgp_pubkey_t *,
+ uint8_t *);
+unsigned pgp_fileread_litdata(const char *, const pgp_litdata_enum,
+ pgp_output_t *);
+unsigned pgp_write_symm_enc_data(const uint8_t *, const int,
+ pgp_output_t *);
+
+#endif /* CREATE_H_ */
diff --git a/libs/netpgp/src/lib/crypto.c b/libs/netpgp/src/lib/crypto.c
new file mode 100644
index 00000000..0d04cd95
--- /dev/null
+++ b/libs/netpgp/src/lib/crypto.c
@@ -0,0 +1,612 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: crypto.c,v 1.36 2014/02/17 07:39:19 agc Exp $");
+#endif
+
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#include
+
+#include "types.h"
+#include "crypto.h"
+#include "readerwriter.h"
+#include "memory.h"
+#include "netpgpdefs.h"
+#include "signature.h"
+
+/**
+\ingroup Core_MPI
+\brief Decrypt and unencode MPI
+\param buf Buffer in which to write decrypted unencoded MPI
+\param buflen Length of buffer
+\param encmpi
+\param seckey
+\return length of MPI
+\note only RSA at present
+*/
+int
+pgp_decrypt_decode_mpi(uint8_t *buf,
+ unsigned buflen,
+ const BIGNUM *g_to_k,
+ const BIGNUM *encmpi,
+ const pgp_seckey_t *seckey)
+{
+ unsigned mpisize;
+ uint8_t encmpibuf[NETPGP_BUFSIZ];
+ uint8_t mpibuf[NETPGP_BUFSIZ];
+ uint8_t gkbuf[NETPGP_BUFSIZ];
+ int i;
+ int n;
+
+ mpisize = (unsigned)BN_num_bytes(encmpi);
+ /* MPI can't be more than 65,536 */
+ if (mpisize > sizeof(encmpibuf)) {
+ (void) fprintf(stderr, "mpisize too big %u\n", mpisize);
+ return -1;
+ }
+ switch (seckey->pubkey.alg) {
+ case PGP_PKA_RSA:
+ BN_bn2bin(encmpi, encmpibuf);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "encrypted", encmpibuf, 16);
+ }
+ n = pgp_rsa_private_decrypt(mpibuf, encmpibuf,
+ (unsigned)(BN_num_bits(encmpi) + 7) / 8,
+ &seckey->key.rsa, &seckey->pubkey.key.rsa);
+ if (n == -1) {
+ (void) fprintf(stderr, "ops_rsa_private_decrypt failure\n");
+ return -1;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "decrypted", mpibuf, 16);
+ }
+ if (n <= 0) {
+ return -1;
+ }
+ /* Decode EME-PKCS1_V1_5 (RFC 2437). */
+ if (mpibuf[0] != 0 || mpibuf[1] != 2) {
+ return -1;
+ }
+ /* Skip the random bytes. */
+ for (i = 2; i < n && mpibuf[i]; ++i) {
+ }
+ if (i == n || i < 10) {
+ return -1;
+ }
+ /* Skip the zero */
+ i += 1;
+ /* this is the unencoded m buf */
+ if ((unsigned) (n - i) <= buflen) {
+ (void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "decoded m", buf, (size_t)(n - i));
+ }
+ return n - i;
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ (void) BN_bn2bin(g_to_k, gkbuf);
+ (void) BN_bn2bin(encmpi, encmpibuf);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "encrypted", encmpibuf, 16);
+ }
+ n = pgp_elgamal_private_decrypt(mpibuf, gkbuf, encmpibuf,
+ (unsigned)BN_num_bytes(encmpi),
+ &seckey->key.elgamal, &seckey->pubkey.key.elgamal);
+ if (n == -1) {
+ (void) fprintf(stderr, "ops_elgamal_private_decrypt failure\n");
+ return -1;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "decrypted", mpibuf, 16);
+ }
+ if (n <= 0) {
+ return -1;
+ }
+ /* Decode EME-PKCS1_V1_5 (RFC 2437). */
+ if (mpibuf[0] != 2) {
+ fprintf(stderr, "mpibuf mismatch\n");
+ return -1;
+ }
+ /* Skip the random bytes. */
+ for (i = 1; i < n && mpibuf[i]; ++i) {
+ }
+ if (i == n || i < 10) {
+ fprintf(stderr, "175 n %d\n", n);
+ return -1;
+ }
+ /* Skip the zero */
+ i += 1;
+ /* this is the unencoded m buf */
+ if ((unsigned) (n - i) <= buflen) {
+ (void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "decoded m", buf, (size_t)(n - i));
+ }
+ return n - i;
+ default:
+ (void) fprintf(stderr, "pubkey algorithm wrong\n");
+ return -1;
+ }
+}
+
+/**
+\ingroup Core_MPI
+\brief RSA-encrypt an MPI
+*/
+unsigned
+pgp_rsa_encrypt_mpi(const uint8_t *encoded_m_buf,
+ const size_t sz_encoded_m_buf,
+ const pgp_pubkey_t * pubkey,
+ pgp_pk_sesskey_params_t * skp)
+{
+
+ uint8_t encmpibuf[NETPGP_BUFSIZ];
+ int n;
+
+ if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.rsa.n)) {
+ (void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
+ return 0;
+ }
+
+ n = pgp_rsa_public_encrypt(encmpibuf, encoded_m_buf,
+ sz_encoded_m_buf, &pubkey->key.rsa);
+ if (n == -1) {
+ (void) fprintf(stderr, "pgp_rsa_public_encrypt failure\n");
+ return 0;
+ }
+
+ if (n <= 0)
+ return 0;
+
+ skp->rsa.encrypted_m = BN_bin2bn(encmpibuf, n, NULL);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "encrypted mpi", encmpibuf, 16);
+ }
+ return 1;
+}
+
+/**
+\ingroup Core_MPI
+\brief Elgamal-encrypt an MPI
+*/
+unsigned
+pgp_elgamal_encrypt_mpi(const uint8_t *encoded_m_buf,
+ const size_t sz_encoded_m_buf,
+ const pgp_pubkey_t * pubkey,
+ pgp_pk_sesskey_params_t * skp)
+{
+
+ uint8_t encmpibuf[NETPGP_BUFSIZ];
+ uint8_t g_to_k[NETPGP_BUFSIZ];
+ int n;
+
+ if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.elgamal.p)) {
+ (void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
+ return 0;
+ }
+
+ n = pgp_elgamal_public_encrypt(g_to_k, encmpibuf, encoded_m_buf,
+ sz_encoded_m_buf, &pubkey->key.elgamal);
+ if (n == -1) {
+ (void) fprintf(stderr, "pgp_elgamal_public_encrypt failure\n");
+ return 0;
+ }
+
+ if (n <= 0)
+ return 0;
+
+ skp->elgamal.g_to_k = BN_bin2bn(g_to_k, n / 2, NULL);
+ skp->elgamal.encrypted_m = BN_bin2bn(encmpibuf, n / 2, NULL);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "encrypted mpi", encmpibuf, 16);
+ }
+ return 1;
+}
+
+static pgp_cb_ret_t
+write_parsed_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("write_parsed_cb: ");
+ pgp_print_packet(&cbinfo->printstate, pkt);
+ }
+ if (pkt->tag != PGP_PTAG_CT_UNARMOURED_TEXT && cbinfo->printstate.skipping) {
+ puts("...end of skip");
+ cbinfo->printstate.skipping = 0;
+ }
+ switch (pkt->tag) {
+ case PGP_PTAG_CT_UNARMOURED_TEXT:
+ printf("PGP_PTAG_CT_UNARMOURED_TEXT\n");
+ if (!cbinfo->printstate.skipping) {
+ puts("Skipping...");
+ cbinfo->printstate.skipping = 1;
+ }
+ if (fwrite(content->unarmoured_text.data, 1,
+ content->unarmoured_text.length, stdout) != content->unarmoured_text.length) {
+ fprintf(stderr, "unable to write unarmoured text data\n");
+ cbinfo->printstate.skipping = 1;
+ }
+ break;
+
+ case PGP_PTAG_CT_PK_SESSION_KEY:
+ return pgp_pk_sesskey_cb(pkt, cbinfo);
+
+ case PGP_GET_SECKEY:
+ if (cbinfo->sshseckey) {
+ *content->get_seckey.seckey = cbinfo->sshseckey;
+ return PGP_KEEP_MEMORY;
+ }
+ return pgp_get_seckey_cb(pkt, cbinfo);
+
+ case PGP_GET_PASSPHRASE:
+ return cbinfo->cryptinfo.getpassphrase(pkt, cbinfo);
+
+ case PGP_PTAG_CT_LITDATA_BODY:
+ return pgp_litdata_cb(pkt, cbinfo);
+
+ case PGP_PTAG_CT_ARMOUR_HEADER:
+ case PGP_PTAG_CT_ARMOUR_TRAILER:
+ case PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
+ case PGP_PTAG_CT_COMPRESSED:
+ case PGP_PTAG_CT_LITDATA_HEADER:
+ case PGP_PTAG_CT_SE_IP_DATA_BODY:
+ case PGP_PTAG_CT_SE_IP_DATA_HEADER:
+ case PGP_PTAG_CT_SE_DATA_BODY:
+ case PGP_PTAG_CT_SE_DATA_HEADER:
+ /* Ignore these packets */
+ /* They're handled in parse_packet() */
+ /* and nothing else needs to be done */
+ break;
+
+ default:
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n",
+ pkt->tag,
+ pkt->tag);
+ }
+ break;
+ }
+
+ return PGP_RELEASE_MEMORY;
+}
+
+/**
+\ingroup HighLevel_Crypto
+Encrypt a file
+\param infile Name of file to be encrypted
+\param outfile Name of file to write to. If NULL, name is constructed from infile
+\param pubkey Public Key to encrypt file for
+\param use_armour Write armoured text, if set
+\param allow_overwrite Allow output file to be overwrwritten if it exists
+\return 1 if OK; else 0
+*/
+unsigned
+pgp_encrypt_file(pgp_io_t *io,
+ const char *infile,
+ const char *outfile,
+ const pgp_key_t *key,
+ const unsigned use_armour,
+ const unsigned allow_overwrite,
+ const char *cipher)
+{
+ pgp_output_t *output;
+ pgp_memory_t *inmem;
+ int fd_out;
+
+ __PGP_USED(io);
+ inmem = pgp_memory_new();
+ if (!pgp_mem_readfile(inmem, infile)) {
+ return 0;
+ }
+ fd_out = pgp_setup_file_write(&output, outfile, allow_overwrite);
+ if (fd_out < 0) {
+ pgp_memory_free(inmem);
+ return 0;
+ }
+
+ /* set armoured/not armoured here */
+ if (use_armour) {
+ pgp_writer_push_armor_msg(output);
+ }
+
+ /* Push the encrypted writer */
+ if (!pgp_push_enc_se_ip(output, key, cipher)) {
+ pgp_memory_free(inmem);
+ return 0;
+ }
+
+ /* This does the writing */
+ pgp_write(output, pgp_mem_data(inmem), (unsigned)pgp_mem_len(inmem));
+
+ /* tidy up */
+ pgp_memory_free(inmem);
+ pgp_teardown_file_write(output, fd_out);
+
+ return 1;
+}
+
+/* encrypt the contents of the input buffer, and return the mem structure */
+pgp_memory_t *
+pgp_encrypt_buf(pgp_io_t *io,
+ const void *input,
+ const size_t insize,
+ const pgp_key_t *pubkey,
+ const unsigned use_armour,
+ const char *cipher)
+{
+ pgp_output_t *output;
+ pgp_memory_t *outmem;
+
+ __PGP_USED(io);
+ if (input == NULL) {
+ (void) fprintf(io->errs,
+ "pgp_encrypt_buf: null memory\n");
+ return 0;
+ }
+
+ pgp_setup_memory_write(&output, &outmem, insize);
+
+ /* set armoured/not armoured here */
+ if (use_armour) {
+ pgp_writer_push_armor_msg(output);
+ }
+
+ /* Push the encrypted writer */
+ pgp_push_enc_se_ip(output, pubkey, cipher);
+
+ /* This does the writing */
+ pgp_write(output, input, (unsigned)insize);
+
+ /* tidy up */
+ pgp_writer_close(output);
+ pgp_output_delete(output);
+
+ return outmem;
+}
+
+/**
+ \ingroup HighLevel_Crypto
+ \brief Decrypt a file.
+ \param infile Name of file to be decrypted
+ \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
+ \param keyring Keyring to use
+ \param use_armour Expect armoured text, if set
+ \param allow_overwrite Allow output file to overwritten, if set.
+ \param getpassfunc Callback to use to get passphrase
+*/
+
+unsigned
+pgp_decrypt_file(pgp_io_t *io,
+ const char *infile,
+ const char *outfile,
+ pgp_keyring_t *secring,
+ pgp_keyring_t *pubring,
+ const unsigned use_armour,
+ const unsigned allow_overwrite,
+ const unsigned sshkeys,
+ void *passfp,
+ int numtries,
+ pgp_cbfunc_t *getpassfunc)
+{
+ pgp_stream_t *parse = NULL;
+ const int printerrors = 1;
+ char *filename = NULL;
+ int fd_in;
+ int fd_out;
+
+ /* setup for reading from given input file */
+ fd_in = pgp_setup_file_read(io, &parse, infile,
+ NULL,
+ write_parsed_cb,
+ 0);
+ if (fd_in < 0) {
+ perror(infile);
+ return 0;
+ }
+ /* setup output filename */
+ if (outfile) {
+ fd_out = pgp_setup_file_write(&parse->cbinfo.output, outfile,
+ allow_overwrite);
+ if (fd_out < 0) {
+ perror(outfile);
+ pgp_teardown_file_read(parse, fd_in);
+ return 0;
+ }
+ } else {
+ const int suffixlen = 4;
+ const char *suffix = infile + strlen(infile) - suffixlen;
+ unsigned filenamelen;
+
+ if (strcmp(suffix, ".gpg") == 0 ||
+ strcmp(suffix, ".asc") == 0) {
+ filenamelen = (unsigned)(strlen(infile) - strlen(suffix));
+ if ((filename = calloc(1, filenamelen + 1)) == NULL) {
+ (void) fprintf(stderr, "can't allocate %" PRIsize "d bytes\n",
+ (size_t)(filenamelen + 1));
+ return 0;
+ }
+ (void) strncpy(filename, infile, filenamelen);
+ filename[filenamelen] = 0x0;
+ }
+
+ fd_out = pgp_setup_file_write(&parse->cbinfo.output,
+ filename, allow_overwrite);
+ if (fd_out < 0) {
+ perror(filename);
+ free(filename);
+ pgp_teardown_file_read(parse, fd_in);
+ return 0;
+ }
+ }
+
+ /* \todo check for suffix matching armour param */
+
+ /* setup for writing decrypted contents to given output file */
+
+ /* setup keyring and passphrase callback */
+ parse->cbinfo.cryptinfo.secring = secring;
+ parse->cbinfo.passfp = passfp;
+ parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
+ parse->cbinfo.cryptinfo.pubring = pubring;
+ parse->cbinfo.sshseckey = (sshkeys) ? &secring->keys[0].key.seckey : NULL;
+ parse->cbinfo.numtries = numtries;
+
+ /* Set up armour/passphrase options */
+ if (use_armour) {
+ pgp_reader_push_dearmour(parse);
+ }
+
+ /* Do it */
+ pgp_parse(parse, printerrors);
+
+ /* Unsetup */
+ if (use_armour) {
+ pgp_reader_pop_dearmour(parse);
+ }
+
+ /* if we didn't get the passphrase, unlink output file */
+ if (!parse->cbinfo.gotpass) {
+ (void) unlink((filename) ? filename : outfile);
+ }
+
+ if (filename) {
+ pgp_teardown_file_write(parse->cbinfo.output, fd_out);
+ free(filename);
+ }
+ pgp_teardown_file_read(parse, fd_in);
+ /* \todo cleardown crypt */
+
+ return 1;
+}
+
+/* decrypt an area of memory */
+pgp_memory_t *
+pgp_decrypt_buf(pgp_io_t *io,
+ const void *input,
+ const size_t insize,
+ pgp_keyring_t *secring,
+ pgp_keyring_t *pubring,
+ const unsigned use_armour,
+ const unsigned sshkeys,
+ void *passfp,
+ int numtries,
+ pgp_cbfunc_t *getpassfunc)
+{
+ pgp_stream_t *parse = NULL;
+ pgp_memory_t *outmem;
+ pgp_memory_t *inmem;
+ const int printerrors = 1;
+
+ if (input == NULL) {
+ (void) fprintf(io->errs,
+ "pgp_encrypt_buf: null memory\n");
+ return 0;
+ }
+
+ inmem = pgp_memory_new();
+ pgp_memory_add(inmem, input, insize);
+
+ /* set up to read from memory */
+ pgp_setup_memory_read(io, &parse, inmem,
+ NULL,
+ write_parsed_cb,
+ 0);
+
+ /* setup for writing decrypted contents to given output file */
+ pgp_setup_memory_write(&parse->cbinfo.output, &outmem, insize);
+
+ /* setup keyring and passphrase callback */
+ parse->cbinfo.cryptinfo.secring = secring;
+ parse->cbinfo.cryptinfo.pubring = pubring;
+ parse->cbinfo.passfp = passfp;
+ parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
+ parse->cbinfo.sshseckey = (sshkeys) ? &secring->keys[0].key.seckey : NULL;
+ parse->cbinfo.numtries = numtries;
+
+ /* Set up armour/passphrase options */
+ if (use_armour) {
+ pgp_reader_push_dearmour(parse);
+ }
+
+ /* Do it */
+ pgp_parse(parse, printerrors);
+
+ /* Unsetup */
+ if (use_armour) {
+ pgp_reader_pop_dearmour(parse);
+ }
+
+ /* tidy up */
+ pgp_teardown_memory_read(parse, inmem);
+
+ pgp_writer_close(parse->cbinfo.output);
+ pgp_output_delete(parse->cbinfo.output);
+
+ /* if we didn't get the passphrase, return NULL */
+ return (parse->cbinfo.gotpass) ? outmem : NULL;
+}
diff --git a/libs/netpgp/src/lib/crypto.h b/libs/netpgp/src/lib/crypto.h
new file mode 100644
index 00000000..ff631efe
--- /dev/null
+++ b/libs/netpgp/src/lib/crypto.h
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+
+#ifndef CRYPTO_H_
+#define CRYPTO_H_
+
+#include "keyring.h"
+#include "packet.h"
+#include "memory.h"
+#include "packet-parse.h"
+
+#include
+
+#define PGP_MIN_HASH_SIZE 16
+
+/** pgp_hash_t */
+struct pgp_hash_t {
+ pgp_hash_alg_t alg; /* algorithm */
+ size_t size; /* size */
+ const char *name; /* what it's known as */
+ int (*init)(pgp_hash_t *);
+ void (*add)(pgp_hash_t *, const uint8_t *, unsigned);
+ unsigned (*finish)(pgp_hash_t *, uint8_t *);
+ void *data; /* blob for data */
+};
+
+/** pgp_crypt_t */
+struct pgp_crypt_t {
+ pgp_symm_alg_t alg;
+ size_t blocksize;
+ size_t keysize;
+ void (*set_iv)(pgp_crypt_t *, const uint8_t *);
+ void (*set_crypt_key)(pgp_crypt_t *, const uint8_t *);
+ int (*base_init)(pgp_crypt_t *);
+ void (*decrypt_resync)(pgp_crypt_t *);
+ /* encrypt/decrypt one block */
+ void (*block_encrypt)(pgp_crypt_t *, void *, const void *);
+ void (*block_decrypt)(pgp_crypt_t *, void *, const void *);
+ /* Standard CFB encrypt/decrypt (as used by Sym Enc Int Prot packets) */
+ void (*cfb_encrypt)(pgp_crypt_t *, void *, const void *, size_t);
+ void (*cfb_decrypt)(pgp_crypt_t *, void *, const void *, size_t);
+ void (*decrypt_finish)(pgp_crypt_t *);
+ uint8_t iv[PGP_MAX_BLOCK_SIZE];
+ uint8_t civ[PGP_MAX_BLOCK_SIZE];
+ uint8_t siv[PGP_MAX_BLOCK_SIZE];
+ /* siv is needed for weird v3 resync */
+ uint8_t key[PGP_MAX_KEY_SIZE];
+ int num;
+ /* num is offset - see openssl _encrypt doco */
+ void *encrypt_key;
+ void *decrypt_key;
+};
+
+void pgp_crypto_finish(void);
+void pgp_hash_md5(pgp_hash_t *);
+void pgp_hash_sha1(pgp_hash_t *);
+void pgp_hash_sha256(pgp_hash_t *);
+void pgp_hash_sha512(pgp_hash_t *);
+void pgp_hash_sha384(pgp_hash_t *);
+void pgp_hash_sha224(pgp_hash_t *);
+void pgp_hash_any(pgp_hash_t *, pgp_hash_alg_t);
+pgp_hash_alg_t pgp_str_to_hash_alg(const char *);
+const char *pgp_text_from_hash(pgp_hash_t *);
+unsigned pgp_hash_size(pgp_hash_alg_t);
+unsigned pgp_hash(uint8_t *, pgp_hash_alg_t, const void *, size_t);
+
+void pgp_hash_add_int(pgp_hash_t *, unsigned, unsigned);
+
+unsigned pgp_dsa_verify(const uint8_t *, size_t,
+ const pgp_dsa_sig_t *,
+ const pgp_dsa_pubkey_t *);
+
+int pgp_rsa_public_decrypt(uint8_t *, const uint8_t *, size_t,
+ const pgp_rsa_pubkey_t *);
+int pgp_rsa_public_encrypt(uint8_t *, const uint8_t *, size_t,
+ const pgp_rsa_pubkey_t *);
+
+int pgp_rsa_private_encrypt(uint8_t *, const uint8_t *, size_t,
+ const pgp_rsa_seckey_t *, const pgp_rsa_pubkey_t *);
+int pgp_rsa_private_decrypt(uint8_t *, const uint8_t *, size_t,
+ const pgp_rsa_seckey_t *, const pgp_rsa_pubkey_t *);
+
+int pgp_elgamal_public_encrypt(uint8_t *, uint8_t *, const uint8_t *, size_t,
+ const pgp_elgamal_pubkey_t *);
+int pgp_elgamal_private_decrypt(uint8_t *, const uint8_t *, const uint8_t *, size_t,
+ const pgp_elgamal_seckey_t *, const pgp_elgamal_pubkey_t *);
+
+pgp_symm_alg_t pgp_str_to_cipher(const char *);
+unsigned pgp_block_size(pgp_symm_alg_t);
+unsigned pgp_key_size(pgp_symm_alg_t);
+
+int pgp_decrypt_data(pgp_content_enum, pgp_region_t *,
+ pgp_stream_t *);
+
+int pgp_crypt_any(pgp_crypt_t *, pgp_symm_alg_t);
+void pgp_decrypt_init(pgp_crypt_t *);
+void pgp_encrypt_init(pgp_crypt_t *);
+size_t pgp_decrypt_se(pgp_crypt_t *, void *, const void *, size_t);
+size_t pgp_encrypt_se(pgp_crypt_t *, void *, const void *, size_t);
+size_t pgp_decrypt_se_ip(pgp_crypt_t *, void *, const void *, size_t);
+size_t pgp_encrypt_se_ip(pgp_crypt_t *, void *, const void *, size_t);
+unsigned pgp_is_sa_supported(pgp_symm_alg_t);
+
+void pgp_reader_push_decrypt(pgp_stream_t *, pgp_crypt_t *,
+ pgp_region_t *);
+void pgp_reader_pop_decrypt(pgp_stream_t *);
+
+/* Hash everything that's read */
+void pgp_reader_push_hash(pgp_stream_t *, pgp_hash_t *);
+void pgp_reader_pop_hash(pgp_stream_t *);
+
+int pgp_decrypt_decode_mpi(uint8_t *, unsigned, const BIGNUM *,
+ const BIGNUM *, const pgp_seckey_t *);
+
+unsigned pgp_rsa_encrypt_mpi(const uint8_t *, const size_t,
+ const pgp_pubkey_t *,
+ pgp_pk_sesskey_params_t *);
+unsigned pgp_elgamal_encrypt_mpi(const uint8_t *, const size_t,
+ const pgp_pubkey_t *,
+ pgp_pk_sesskey_params_t *);
+
+/* Encrypt everything that's written */
+struct pgp_key_data;
+void pgp_writer_push_encrypt(pgp_output_t *,
+ const struct pgp_key_data *);
+
+unsigned pgp_encrypt_file(pgp_io_t *, const char *, const char *,
+ const pgp_key_t *,
+ const unsigned, const unsigned, const char *);
+unsigned pgp_decrypt_file(pgp_io_t *,
+ const char *,
+ const char *,
+ pgp_keyring_t *,
+ pgp_keyring_t *,
+ const unsigned,
+ const unsigned,
+ const unsigned,
+ void *,
+ int,
+ pgp_cbfunc_t *);
+
+pgp_memory_t *
+pgp_encrypt_buf(pgp_io_t *, const void *, const size_t,
+ const pgp_key_t *,
+ const unsigned, const char *);
+pgp_memory_t *
+pgp_decrypt_buf(pgp_io_t *,
+ const void *,
+ const size_t,
+ pgp_keyring_t *,
+ pgp_keyring_t *,
+ const unsigned,
+ const unsigned,
+ void *,
+ int,
+ pgp_cbfunc_t *);
+
+/* Keys */
+pgp_key_t *pgp_rsa_new_selfsign_key(const int,
+ const unsigned long, uint8_t *, const char *,
+ const char *);
+
+int pgp_dsa_size(const pgp_dsa_pubkey_t *);
+DSA_SIG *pgp_dsa_sign(uint8_t *, unsigned,
+ const pgp_dsa_seckey_t *,
+ const pgp_dsa_pubkey_t *);
+
+int openssl_read_pem_seckey(const char *, pgp_key_t *, const char *, int);
+
+/** pgp_reader_t */
+struct pgp_reader_t {
+ pgp_reader_func_t *reader; /* reader func to get parse data */
+ pgp_reader_destroyer_t *destroyer;
+ void *arg; /* args to pass to reader function */
+ unsigned accumulate:1; /* set to gather packet data */
+ uint8_t *accumulated; /* the accumulated data */
+ unsigned asize; /* size of the buffer */
+ unsigned alength;/* used buffer */
+ unsigned position; /* reader-specific offset */
+ pgp_reader_t *next;
+ pgp_stream_t *parent;/* parent parse_info structure */
+};
+
+
+/** pgp_cryptinfo_t
+ Encrypt/decrypt settings
+*/
+struct pgp_cryptinfo_t {
+ char *passphrase;
+ pgp_keyring_t *secring;
+ const pgp_key_t *keydata;
+ pgp_cbfunc_t *getpassphrase;
+ pgp_keyring_t *pubring;
+};
+
+/** pgp_cbdata_t */
+struct pgp_cbdata_t {
+ pgp_cbfunc_t *cbfunc; /* callback function */
+ void *arg; /* args to pass to callback func */
+ pgp_error_t **errors; /* address of error stack */
+ pgp_cbdata_t *next;
+ pgp_output_t *output; /* when writing out parsed info */
+ pgp_io_t *io; /* error/output messages */
+ void *passfp; /* fp for passphrase input */
+ pgp_cryptinfo_t cryptinfo; /* used when decrypting */
+ pgp_printstate_t printstate; /* used to keep printing state */
+ pgp_seckey_t *sshseckey; /* secret key for ssh */
+ int numtries; /* # of passphrase attempts */
+ int gotpass; /* when passphrase entered */
+};
+
+/** pgp_hashtype_t */
+typedef struct {
+ pgp_hash_t hash; /* hashes we should hash data with */
+ uint8_t keyid[PGP_KEY_ID_SIZE];
+} pgp_hashtype_t;
+
+#define NTAGS 0x100 /* == 256 */
+
+/** \brief Structure to hold information about a packet parse.
+ *
+ * This information includes options about the parse:
+ * - whether the packet contents should be accumulated or not
+ * - whether signature subpackets should be parsed or left raw
+ *
+ * It contains options specific to the parsing of armoured data:
+ * - whether headers are allowed in armoured data without a gap
+ * - whether a blank line is allowed at the start of the armoured data
+ *
+ * It also specifies :
+ * - the callback function to use and its arguments
+ * - the reader function to use and its arguments
+ *
+ * It also contains information about the current state of the parse:
+ * - offset from the beginning
+ * - the accumulated data, if any
+ * - the size of the buffer, and how much has been used
+ *
+ * It has a linked list of errors.
+ */
+
+struct pgp_stream_t {
+ uint8_t ss_raw[NTAGS / 8];
+ /* 1 bit / sig-subpkt type; set to get raw data */
+ uint8_t ss_parsed[NTAGS / 8];
+ /* 1 bit / sig-subpkt type; set to get parsed data */
+ pgp_reader_t readinfo;
+ pgp_cbdata_t cbinfo;
+ pgp_error_t *errors;
+ void *io; /* io streams */
+ pgp_crypt_t decrypt;
+ pgp_cryptinfo_t cryptinfo;
+ size_t hashc;
+ pgp_hashtype_t *hashes;
+ unsigned reading_v3_secret:1;
+ unsigned reading_mpi_len:1;
+ unsigned exact_read:1;
+ unsigned partial_read:1;
+ unsigned coalescing:1;
+ /* used for partial length coalescing */
+ unsigned virtualc;
+ unsigned virtualoff;
+ uint8_t *virtualpkt;
+};
+
+#endif /* CRYPTO_H_ */
diff --git a/libs/netpgp/src/lib/defs.h b/libs/netpgp/src/lib/defs.h
new file mode 100644
index 00000000..2c62eb8d
--- /dev/null
+++ b/libs/netpgp/src/lib/defs.h
@@ -0,0 +1,92 @@
+/* $NetBSD: defs.h,v 1.2 2009/12/06 17:43:05 agc Exp $ */
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef DEFS_H_
+#define DEFS_H_
+
+#include
+#include
+
+#ifdef HAVE_INTTYPES_H
+#include
+#endif
+
+#ifdef HAVE_STDINT_H
+#include
+#endif
+
+#include
+#include
+#include
+
+#define NEWARRAY(type,ptr,size,where,action) do { \
+ if ((ptr = calloc(sizeof(type), (unsigned)(size))) == NULL) { \
+ (void) fprintf(stderr, "%s: can't allocate %lu bytes\n", \
+ where, (unsigned long)(size * sizeof(type))); \
+ action; \
+ } \
+} while( /* CONSTCOND */ 0)
+
+#define RENEW(type,ptr,size,where,action) do { \
+ type *_newptr; \
+ _newptr = realloc(ptr, (size_t)(sizeof(type) * (size))); \
+ if (_newptr == NULL) { \
+ (void) fprintf(stderr, "%s: can't realloc %lu bytes\n", \
+ where, (unsigned long)(size * sizeof(type))); \
+ action; \
+ } else { \
+ ptr = _newptr; \
+ } \
+} while( /* CONSTCOND */ 0)
+
+#define NEW(type, ptr, where, action) NEWARRAY(type, ptr, 1, where, action)
+
+#define FREE(ptr) (void) free(ptr)
+
+#define ALLOC(type, v, size, c, init, incr, where, action) do { \
+ uint32_t _newsize = size; \
+ if (size == 0) { \
+ _newsize = init; \
+ NEWARRAY(type, v, _newsize, where ": new", action); \
+ } else if (c == size) { \
+ _newsize = size + incr; \
+ RENEW(type, v, _newsize, where ": renew", action); \
+ } \
+ size = _newsize; \
+} while( /* CONSTCOND */ 0)
+
+#define DEFINE_ARRAY(name, type) \
+typedef struct name { \
+ uint32_t c; \
+ uint32_t size; \
+ type *v; \
+} name
+
+#endif /* !DEFS_H_ */
diff --git a/libs/netpgp/src/lib/errors.h b/libs/netpgp/src/lib/errors.h
new file mode 100644
index 00000000..ab518d08
--- /dev/null
+++ b/libs/netpgp/src/lib/errors.h
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+
+#ifndef ERRORS_H_
+#define ERRORS_H_
+
+#include
+
+#ifndef __printflike
+#define __printflike(n, m) __attribute__((format(printf,n,m)))
+#endif
+
+/** error codes */
+/* Remember to add names to map in errors.c */
+typedef enum {
+ PGP_E_OK = 0x0000, /* no error */
+ PGP_E_FAIL = 0x0001, /* general error */
+ PGP_E_SYSTEM_ERROR = 0x0002, /* system error, look at errno for
+ * details */
+ PGP_E_UNIMPLEMENTED = 0x0003, /* feature not yet implemented */
+
+ /* reader errors */
+ PGP_E_R = 0x1000, /* general reader error */
+ PGP_E_R_READ_FAILED = PGP_E_R + 1,
+ PGP_E_R_EARLY_EOF = PGP_E_R + 2,
+ PGP_E_R_BAD_FORMAT = PGP_E_R + 3, /* For example, malformed
+ * armour */
+ PGP_E_R_UNSUPPORTED = PGP_E_R + 4,
+ PGP_E_R_UNCONSUMED_DATA = PGP_E_R + 5,
+
+ /* writer errors */
+ PGP_E_W = 0x2000, /* general writer error */
+ PGP_E_W_WRITE_FAILED = PGP_E_W + 1,
+ PGP_E_W_WRITE_TOO_SHORT = PGP_E_W + 2,
+
+ /* parser errors */
+ PGP_E_P = 0x3000, /* general parser error */
+ PGP_E_P_NOT_ENOUGH_DATA = PGP_E_P + 1,
+ PGP_E_P_UNKNOWN_TAG = PGP_E_P + 2,
+ PGP_E_P_PACKET_CONSUMED = PGP_E_P + 3,
+ PGP_E_P_MPI_FORMAT_ERROR = PGP_E_P + 4,
+ PGP_E_P_PACKET_NOT_CONSUMED = PGP_E_P + 5,
+ PGP_E_P_DECOMPRESSION_ERROR = PGP_E_P + 6,
+ PGP_E_P_NO_USERID = PGP_E_P + 7,
+
+ /* creator errors */
+ PGP_E_C = 0x4000, /* general creator error */
+
+ /* validation errors */
+ PGP_E_V = 0x5000, /* general validation error */
+ PGP_E_V_BAD_SIGNATURE = PGP_E_V + 1,
+ PGP_E_V_NO_SIGNATURE = PGP_E_V + 2,
+ PGP_E_V_UNKNOWN_SIGNER = PGP_E_V + 3,
+ PGP_E_V_BAD_HASH = PGP_E_V + 4,
+
+ /* Algorithm support errors */
+ PGP_E_ALG = 0x6000, /* general algorithm error */
+ PGP_E_ALG_UNSUPPORTED_SYMMETRIC_ALG = PGP_E_ALG + 1,
+ PGP_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG = PGP_E_ALG + 2,
+ PGP_E_ALG_UNSUPPORTED_SIGNATURE_ALG = PGP_E_ALG + 3,
+ PGP_E_ALG_UNSUPPORTED_HASH_ALG = PGP_E_ALG + 4,
+ PGP_E_ALG_UNSUPPORTED_COMPRESS_ALG = PGP_E_ALG + 5,
+
+ /* Protocol errors */
+ PGP_E_PROTO = 0x7000, /* general protocol error */
+ PGP_E_PROTO_BAD_SYMMETRIC_DECRYPT = PGP_E_PROTO + 2,
+ PGP_E_PROTO_UNKNOWN_SS = PGP_E_PROTO + 3,
+ PGP_E_PROTO_CRITICAL_SS_IGNORED = PGP_E_PROTO + 4,
+ PGP_E_PROTO_BAD_PUBLIC_KEY_VRSN = PGP_E_PROTO + 5,
+ PGP_E_PROTO_BAD_SIGNATURE_VRSN = PGP_E_PROTO + 6,
+ PGP_E_PROTO_BAD_ONE_PASS_SIG_VRSN = PGP_E_PROTO + 7,
+ PGP_E_PROTO_BAD_PKSK_VRSN = PGP_E_PROTO + 8,
+ PGP_E_PROTO_DECRYPTED_MSG_WRONG_LEN = PGP_E_PROTO + 9,
+ PGP_E_PROTO_BAD_SK_CHECKSUM = PGP_E_PROTO + 10
+} pgp_errcode_t;
+
+/** one entry in a linked list of errors */
+typedef struct pgp_error {
+ pgp_errcode_t errcode;
+ int sys_errno; /* irrelevent unless errcode ==
+ * PGP_E_SYSTEM_ERROR */
+ char *comment;
+ const char *file;
+ int line;
+ struct pgp_error *next;
+} pgp_error_t;
+
+const char *pgp_errcode(const pgp_errcode_t);
+
+void
+pgp_push_error(pgp_error_t **, pgp_errcode_t,
+ int,
+ const char *, int, const char *,...) __printflike(6, 7);
+void pgp_print_error(pgp_error_t *);
+void pgp_print_errors(pgp_error_t *);
+void pgp_free_errors(pgp_error_t *);
+int pgp_has_error(pgp_error_t *, pgp_errcode_t);
+
+#define PGP_SYSTEM_ERROR_1(err,code,sys,fmt,arg) do { \
+ pgp_push_error(err,PGP_E_SYSTEM_ERROR,errno,__FILE__,__LINE__,sys);\
+ pgp_push_error(err,code,0,__FILE__,__LINE__,fmt,arg); \
+} while(/*CONSTCOND*/0)
+
+#define PGP_MEMORY_ERROR(err) { \
+ fprintf(stderr, "Memory error\n"); \
+} /* \todo placeholder for better error
+ * handling */
+#define PGP_ERROR_1(err,code,fmt,arg) do { \
+ pgp_push_error(err,code,0,__FILE__,__LINE__,fmt,arg); \
+} while(/*CONSTCOND*/0)
+#define PGP_ERROR_2(err,code,fmt,arg,arg2) do { \
+ pgp_push_error(err,code,0,__FILE__,__LINE__,fmt,arg,arg2); \
+} while(/*CONSTCOND*/0)
+#define PGP_ERROR_3(err,code,fmt,arg,arg2,arg3) do { \
+ pgp_push_error(err,code,0,__FILE__,__LINE__,fmt,arg,arg2,arg3); \
+} while(/*CONSTCOND*/0)
+#define PGP_ERROR_4(err,code,fmt,arg,arg2,arg3,arg4) do { \
+ pgp_push_error(err,code,0,__FILE__,__LINE__,fmt,arg,arg2,arg3,arg4); \
+} while(/*CONSTCOND*/0)
+
+#endif /* ERRORS_H_ */
diff --git a/libs/netpgp/src/lib/keyring.c b/libs/netpgp/src/lib/keyring.c
new file mode 100644
index 00000000..712ee90e
--- /dev/null
+++ b/libs/netpgp/src/lib/keyring.c
@@ -0,0 +1,1151 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: keyring.c,v 1.50 2011/06/25 00:37:44 agc Exp $");
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include
+#endif
+
+#include
+#include
+#include
+
+#ifdef HAVE_TERMIOS_H
+#include
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#include "types.h"
+#include "keyring.h"
+#include "packet-parse.h"
+#include "signature.h"
+#include "netpgpsdk.h"
+#include "readerwriter.h"
+#include "netpgpdefs.h"
+#include "packet.h"
+#include "crypto.h"
+#include "validate.h"
+#include "netpgpdefs.h"
+#include "netpgpdigest.h"
+
+
+
+/**
+ \ingroup HighLevel_Keyring
+
+ \brief Creates a new pgp_key_t struct
+
+ \return A new pgp_key_t struct, initialised to zero.
+
+ \note The returned pgp_key_t struct must be freed after use with pgp_keydata_free.
+*/
+
+pgp_key_t *
+pgp_keydata_new(void)
+{
+ return calloc(1, sizeof(pgp_key_t));
+}
+
+
+/**
+ \ingroup HighLevel_Keyring
+
+ \brief Frees keydata and its memory
+
+ \param keydata Key to be freed.
+
+ \note This frees the keydata itself, as well as any other memory alloc-ed by it.
+*/
+void
+pgp_keydata_free(pgp_key_t *keydata)
+{
+ unsigned n;
+
+ for (n = 0; n < keydata->uidc; ++n) {
+ pgp_userid_free(&keydata->uids[n]);
+ }
+ free(keydata->uids);
+ keydata->uids = NULL;
+ keydata->uidc = 0;
+
+ for (n = 0; n < keydata->packetc; ++n) {
+ pgp_subpacket_free(&keydata->packets[n]);
+ }
+ free(keydata->packets);
+ keydata->packets = NULL;
+ keydata->packetc = 0;
+
+ if (keydata->type == PGP_PTAG_CT_PUBLIC_KEY) {
+ pgp_pubkey_free(&keydata->key.pubkey);
+ } else {
+ pgp_seckey_free(&keydata->key.seckey);
+ }
+
+ free(keydata);
+}
+
+/**
+ \ingroup HighLevel_KeyGeneral
+
+ \brief Returns the public key in the given keydata.
+ \param keydata
+
+ \return Pointer to public key
+
+ \note This is not a copy, do not free it after use.
+*/
+
+const pgp_pubkey_t *
+pgp_get_pubkey(const pgp_key_t *keydata)
+{
+ return (keydata->type == PGP_PTAG_CT_PUBLIC_KEY) ?
+ &keydata->key.pubkey :
+ &keydata->key.seckey.pubkey;
+}
+
+/**
+\ingroup HighLevel_KeyGeneral
+
+\brief Check whether this is a secret key or not.
+*/
+
+unsigned
+pgp_is_key_secret(const pgp_key_t *data)
+{
+ return data->type != PGP_PTAG_CT_PUBLIC_KEY;
+}
+
+/**
+ \ingroup HighLevel_KeyGeneral
+
+ \brief Returns the secret key in the given keydata.
+
+ \note This is not a copy, do not free it after use.
+
+ \note This returns a const. If you need to be able to write to this
+ pointer, use pgp_get_writable_seckey
+*/
+
+const pgp_seckey_t *
+pgp_get_seckey(const pgp_key_t *data)
+{
+ return (data->type == PGP_PTAG_CT_SECRET_KEY) ?
+ &data->key.seckey : NULL;
+}
+
+/**
+ \ingroup HighLevel_KeyGeneral
+
+ \brief Returns the secret key in the given keydata.
+
+ \note This is not a copy, do not free it after use.
+
+ \note If you do not need to be able to modify this key, there is an
+ equivalent read-only function pgp_get_seckey.
+*/
+
+pgp_seckey_t *
+pgp_get_writable_seckey(pgp_key_t *data)
+{
+ return (data->type == PGP_PTAG_CT_SECRET_KEY) ?
+ &data->key.seckey : NULL;
+}
+
+/* utility function to zero out memory */
+void
+pgp_forget(void *vp, unsigned size)
+{
+ (void) memset(vp, 0x0, size);
+}
+
+typedef struct {
+ FILE *passfp;
+ const pgp_key_t *key;
+ char *passphrase;
+ pgp_seckey_t *seckey;
+} decrypt_t;
+
+static pgp_cb_ret_t
+decrypt_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+ decrypt_t *decrypt;
+ char pass[MAX_PASSPHRASE_LENGTH];
+
+ decrypt = pgp_callback_arg(cbinfo);
+ switch (pkt->tag) {
+ case PGP_PARSER_PTAG:
+ case PGP_PTAG_CT_USER_ID:
+ case PGP_PTAG_CT_SIGNATURE:
+ case PGP_PTAG_CT_SIGNATURE_HEADER:
+ case PGP_PTAG_CT_SIGNATURE_FOOTER:
+ case PGP_PTAG_CT_TRUST:
+ break;
+
+ case PGP_GET_PASSPHRASE:
+ (void) pgp_getpassphrase(decrypt->passfp, pass, sizeof(pass));
+ *content->skey_passphrase.passphrase = netpgp_strdup(pass);
+ pgp_forget(pass, (unsigned)sizeof(pass));
+ return PGP_KEEP_MEMORY;
+
+ case PGP_PARSER_ERRCODE:
+ switch (content->errcode.errcode) {
+ case PGP_E_P_MPI_FORMAT_ERROR:
+ /* Generally this means a bad passphrase */
+ fprintf(stderr, "Bad passphrase!\n");
+ return PGP_RELEASE_MEMORY;
+
+ case PGP_E_P_PACKET_CONSUMED:
+ /* And this is because of an error we've accepted */
+ return PGP_RELEASE_MEMORY;
+ default:
+ break;
+ }
+ (void) fprintf(stderr, "parse error: %s\n",
+ pgp_errcode(content->errcode.errcode));
+ return PGP_FINISHED;
+
+ case PGP_PARSER_ERROR:
+ fprintf(stderr, "parse error: %s\n", content->error);
+ return PGP_FINISHED;
+
+ case PGP_PTAG_CT_SECRET_KEY:
+ if ((decrypt->seckey = calloc(1, sizeof(*decrypt->seckey))) == NULL) {
+ (void) fprintf(stderr, "decrypt_cb: bad alloc\n");
+ return PGP_FINISHED;
+ }
+ decrypt->seckey->checkhash = calloc(1, PGP_CHECKHASH_SIZE);
+ *decrypt->seckey = content->seckey;
+ return PGP_KEEP_MEMORY;
+
+ case PGP_PARSER_PACKET_END:
+ /* nothing to do */
+ break;
+
+ default:
+ fprintf(stderr, "Unexpected tag %d (0x%x)\n", pkt->tag,
+ pkt->tag);
+ return PGP_FINISHED;
+ }
+
+ return PGP_RELEASE_MEMORY;
+}
+
+/**
+\ingroup Core_Keys
+\brief Decrypts secret key from given keydata with given passphrase
+\param key Key from which to get secret key
+\param passphrase Passphrase to use to decrypt secret key
+\return secret key
+*/
+pgp_seckey_t *
+pgp_decrypt_seckey(const pgp_key_t *key, void *passfp)
+{
+ pgp_stream_t *stream;
+ const int printerrors = 1;
+ decrypt_t decrypt;
+
+ (void) memset(&decrypt, 0x0, sizeof(decrypt));
+ decrypt.key = key;
+ decrypt.passfp = passfp;
+ stream = pgp_new(sizeof(*stream));
+ pgp_keydata_reader_set(stream, key);
+ pgp_set_callback(stream, decrypt_cb, &decrypt);
+ stream->readinfo.accumulate = 1;
+ pgp_parse(stream, !printerrors);
+ return decrypt.seckey;
+}
+
+/**
+\ingroup Core_Keys
+\brief Set secret key in content
+\param content Content to be set
+\param key Keydata to get secret key from
+*/
+void
+pgp_set_seckey(pgp_contents_t *cont, const pgp_key_t *key)
+{
+ *cont->get_seckey.seckey = &key->key.seckey;
+}
+
+/**
+\ingroup Core_Keys
+\brief Get Key ID from keydata
+\param key Keydata to get Key ID from
+\return Pointer to Key ID inside keydata
+*/
+const uint8_t *
+pgp_get_key_id(const pgp_key_t *key)
+{
+ return key->sigid;
+}
+
+/**
+\ingroup Core_Keys
+\brief How many User IDs in this key?
+\param key Keydata to check
+\return Num of user ids
+*/
+unsigned
+pgp_get_userid_count(const pgp_key_t *key)
+{
+ return key->uidc;
+}
+
+/**
+\ingroup Core_Keys
+\brief Get indexed user id from key
+\param key Key to get user id from
+\param index Which key to get
+\return Pointer to requested user id
+*/
+const uint8_t *
+pgp_get_userid(const pgp_key_t *key, unsigned subscript)
+{
+ return key->uids[subscript];
+}
+
+/**
+ \ingroup HighLevel_Supported
+ \brief Checks whether key's algorithm and type are supported by OpenPGP::SDK
+ \param keydata Key to be checked
+ \return 1 if key algorithm and type are supported by OpenPGP::SDK; 0 if not
+*/
+
+unsigned
+pgp_is_key_supported(const pgp_key_t *key)
+{
+ if (key->type == PGP_PTAG_CT_PUBLIC_KEY) {
+ switch(key->key.pubkey.alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ return 1;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* \todo check where userid pointers are copied */
+/**
+\ingroup Core_Keys
+\brief Copy user id, including contents
+\param dst Destination User ID
+\param src Source User ID
+\note If dst already has a userid, it will be freed.
+*/
+static uint8_t *
+copy_userid(uint8_t **dst, const uint8_t *src)
+{
+ size_t len;
+
+ len = strlen((const char *) src);
+ if (*dst) {
+ free(*dst);
+ }
+ if ((*dst = calloc(1, len + 1)) == NULL) {
+ (void) fprintf(stderr, "copy_userid: bad alloc\n");
+ } else {
+ (void) memcpy(*dst, src, len);
+ }
+ return *dst;
+}
+
+/* \todo check where pkt pointers are copied */
+/**
+\ingroup Core_Keys
+\brief Copy packet, including contents
+\param dst Destination packet
+\param src Source packet
+\note If dst already has a packet, it will be freed.
+*/
+static pgp_subpacket_t *
+copy_packet(pgp_subpacket_t *dst, const pgp_subpacket_t *src)
+{
+ if (dst->raw) {
+ free(dst->raw);
+ }
+ if ((dst->raw = calloc(1, src->length)) == NULL) {
+ (void) fprintf(stderr, "copy_packet: bad alloc\n");
+ } else {
+ dst->length = src->length;
+ (void) memcpy(dst->raw, src->raw, src->length);
+ }
+ return dst;
+}
+
+/**
+\ingroup Core_Keys
+\brief Add User ID to key
+\param key Key to which to add User ID
+\param userid User ID to add
+\return Pointer to new User ID
+*/
+uint8_t *
+pgp_add_userid(pgp_key_t *key, const uint8_t *userid)
+{
+ uint8_t **uidp;
+
+ EXPAND_ARRAY(key, uid);
+ /* initialise new entry in array */
+ uidp = &key->uids[key->uidc++];
+ *uidp = NULL;
+ /* now copy it */
+ return copy_userid(uidp, userid);
+}
+
+void print_packet_hex(const pgp_subpacket_t *pkt);
+
+/**
+\ingroup Core_Keys
+\brief Add packet to key
+\param keydata Key to which to add packet
+\param packet Packet to add
+\return Pointer to new packet
+*/
+pgp_subpacket_t *
+pgp_add_subpacket(pgp_key_t *keydata, const pgp_subpacket_t *packet)
+{
+ pgp_subpacket_t *subpktp;
+
+ EXPAND_ARRAY(keydata, packet);
+ /* initialise new entry in array */
+ subpktp = &keydata->packets[keydata->packetc++];
+ subpktp->length = 0;
+ subpktp->raw = NULL;
+ /* now copy it */
+ return copy_packet(subpktp, packet);
+}
+
+/**
+\ingroup Core_Keys
+\brief Add selfsigned User ID to key
+\param keydata Key to which to add user ID
+\param userid Self-signed User ID to add
+\return 1 if OK; else 0
+*/
+unsigned
+pgp_add_selfsigned_userid(pgp_key_t *key, uint8_t *userid)
+{
+ pgp_create_sig_t *sig;
+ pgp_subpacket_t sigpacket;
+ pgp_memory_t *mem_userid = NULL;
+ pgp_output_t *useridoutput = NULL;
+ pgp_memory_t *mem_sig = NULL;
+ pgp_output_t *sigoutput = NULL;
+
+ /*
+ * create signature packet for this userid
+ */
+
+ /* create userid pkt */
+ pgp_setup_memory_write(&useridoutput, &mem_userid, 128);
+ pgp_write_struct_userid(useridoutput, userid);
+
+ /* create sig for this pkt */
+ sig = pgp_create_sig_new();
+ pgp_sig_start_key_sig(sig, &key->key.seckey.pubkey, userid, PGP_CERT_POSITIVE);
+ pgp_add_time(sig, (int64_t)time(NULL), "birth");
+ pgp_add_issuer_keyid(sig, key->sigid);
+ pgp_add_primary_userid(sig, 1);
+ pgp_end_hashed_subpkts(sig);
+
+ pgp_setup_memory_write(&sigoutput, &mem_sig, 128);
+ pgp_write_sig(sigoutput, sig, &key->key.seckey.pubkey, &key->key.seckey);
+
+ /* add this packet to key */
+ sigpacket.length = pgp_mem_len(mem_sig);
+ sigpacket.raw = pgp_mem_data(mem_sig);
+
+ /* add userid to key */
+ (void) pgp_add_userid(key, userid);
+ (void) pgp_add_subpacket(key, &sigpacket);
+
+ /* cleanup */
+ pgp_create_sig_delete(sig);
+ pgp_output_delete(useridoutput);
+ pgp_output_delete(sigoutput);
+ pgp_memory_free(mem_userid);
+ pgp_memory_free(mem_sig);
+
+ return 1;
+}
+
+/**
+\ingroup Core_Keys
+\brief Initialise pgp_key_t
+\param keydata Keydata to initialise
+\param type PGP_PTAG_CT_PUBLIC_KEY or PGP_PTAG_CT_SECRET_KEY
+*/
+void
+pgp_keydata_init(pgp_key_t *keydata, const pgp_content_enum type)
+{
+ if (keydata->type != PGP_PTAG_CT_RESERVED) {
+ (void) fprintf(stderr,
+ "pgp_keydata_init: wrong keydata type\n");
+ } else if (type != PGP_PTAG_CT_PUBLIC_KEY &&
+ type != PGP_PTAG_CT_SECRET_KEY) {
+ (void) fprintf(stderr, "pgp_keydata_init: wrong type\n");
+ } else {
+ keydata->type = type;
+ }
+}
+
+/* used to point to data during keyring read */
+typedef struct keyringcb_t {
+ pgp_keyring_t *keyring; /* the keyring we're reading */
+} keyringcb_t;
+
+
+static pgp_cb_ret_t
+cb_keyring_read(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ pgp_keyring_t *keyring;
+ pgp_revoke_t *revocation;
+ pgp_key_t *key;
+ keyringcb_t *cb;
+
+ cb = pgp_callback_arg(cbinfo);
+ keyring = cb->keyring;
+ switch (pkt->tag) {
+ case PGP_PARSER_PTAG:
+ case PGP_PTAG_CT_ENCRYPTED_SECRET_KEY:
+ /* we get these because we didn't prompt */
+ break;
+ case PGP_PTAG_CT_SIGNATURE_HEADER:
+ key = &keyring->keys[keyring->keyc - 1];
+ EXPAND_ARRAY(key, subsig);
+ key->subsigs[key->subsigc].uid = key->uidc - 1;
+ (void) memcpy(&key->subsigs[key->subsigc].sig, &pkt->u.sig,
+ sizeof(pkt->u.sig));
+ key->subsigc += 1;
+ break;
+ case PGP_PTAG_CT_SIGNATURE:
+ key = &keyring->keys[keyring->keyc - 1];
+ EXPAND_ARRAY(key, subsig);
+ key->subsigs[key->subsigc].uid = key->uidc - 1;
+ (void) memcpy(&key->subsigs[key->subsigc].sig, &pkt->u.sig,
+ sizeof(pkt->u.sig));
+ key->subsigc += 1;
+ break;
+ case PGP_PTAG_CT_TRUST:
+ key = &keyring->keys[keyring->keyc - 1];
+ key->subsigs[key->subsigc - 1].trustlevel = pkt->u.ss_trust.level;
+ key->subsigs[key->subsigc - 1].trustamount = pkt->u.ss_trust.amount;
+ break;
+ case PGP_PTAG_SS_KEY_EXPIRY:
+ EXPAND_ARRAY(keyring, key);
+ if (keyring->keyc > 0) {
+ keyring->keys[keyring->keyc - 1].key.pubkey.duration = pkt->u.ss_time;
+ }
+ break;
+ case PGP_PTAG_SS_ISSUER_KEY_ID:
+ key = &keyring->keys[keyring->keyc - 1];
+ (void) memcpy(&key->subsigs[key->subsigc - 1].sig.info.signer_id,
+ pkt->u.ss_issuer,
+ sizeof(pkt->u.ss_issuer));
+ key->subsigs[key->subsigc - 1].sig.info.signer_id_set = 1;
+ break;
+ case PGP_PTAG_SS_CREATION_TIME:
+ key = &keyring->keys[keyring->keyc - 1];
+ key->subsigs[key->subsigc - 1].sig.info.birthtime = pkt->u.ss_time;
+ key->subsigs[key->subsigc - 1].sig.info.birthtime_set = 1;
+ break;
+ case PGP_PTAG_SS_EXPIRATION_TIME:
+ key = &keyring->keys[keyring->keyc - 1];
+ key->subsigs[key->subsigc - 1].sig.info.duration = pkt->u.ss_time;
+ key->subsigs[key->subsigc - 1].sig.info.duration_set = 1;
+ break;
+ case PGP_PTAG_SS_PRIMARY_USER_ID:
+ key = &keyring->keys[keyring->keyc - 1];
+ key->uid0 = key->uidc - 1;
+ break;
+ case PGP_PTAG_SS_REVOCATION_REASON:
+ key = &keyring->keys[keyring->keyc - 1];
+ if (key->uidc == 0) {
+ /* revoke whole key */
+ key->revoked = 1;
+ revocation = &key->revocation;
+ } else {
+ /* revoke the user id */
+ EXPAND_ARRAY(key, revoke);
+ revocation = &key->revokes[key->revokec];
+ key->revokes[key->revokec].uid = key->uidc - 1;
+ key->revokec += 1;
+ }
+ revocation->code = pkt->u.ss_revocation.code;
+ revocation->reason = netpgp_strdup(pgp_show_ss_rr_code(pkt->u.ss_revocation.code));
+ break;
+ case PGP_PTAG_CT_SIGNATURE_FOOTER:
+ case PGP_PARSER_ERRCODE:
+ break;
+
+ default:
+ break;
+ }
+
+ return PGP_RELEASE_MEMORY;
+}
+
+/**
+ \ingroup HighLevel_KeyringRead
+
+ \brief Reads a keyring from a file
+
+ \param keyring Pointer to an existing pgp_keyring_t struct
+ \param armour 1 if file is armoured; else 0
+ \param filename Filename of keyring to be read
+
+ \return pgp 1 if OK; 0 on error
+
+ \note Keyring struct must already exist.
+
+ \note Can be used with either a public or secret keyring.
+
+ \note You must call pgp_keyring_free() after usage to free alloc-ed memory.
+
+ \note If you call this twice on the same keyring struct, without calling
+ pgp_keyring_free() between these calls, you will introduce a memory leak.
+
+ \sa pgp_keyring_read_from_mem()
+ \sa pgp_keyring_free()
+
+*/
+
+unsigned
+pgp_keyring_fileread(pgp_keyring_t *keyring,
+ const unsigned armour,
+ const char *filename)
+{
+ pgp_stream_t *stream;
+ keyringcb_t cb;
+ unsigned res = 1;
+ int fd;
+
+ (void) memset(&cb, 0x0, sizeof(cb));
+ cb.keyring = keyring;
+ stream = pgp_new(sizeof(*stream));
+
+ /* add this for the moment, */
+ /*
+ * \todo need to fix the problems with reading signature subpackets
+ * later
+ */
+
+ /* pgp_parse_options(parse,PGP_PTAG_SS_ALL,PGP_PARSE_RAW); */
+ pgp_parse_options(stream, PGP_PTAG_SS_ALL, PGP_PARSE_PARSED);
+
+#ifdef O_BINARY
+ fd = open(filename, O_RDONLY | O_BINARY);
+#else
+ fd = open(filename, O_RDONLY);
+#endif
+ if (fd < 0) {
+ pgp_stream_delete(stream);
+ perror(filename);
+ return 0;
+ }
+#ifdef USE_MMAP_FOR_FILES
+ pgp_reader_set_mmap(stream, fd);
+#else
+ pgp_reader_set_fd(stream, fd);
+#endif
+
+ pgp_set_callback(stream, cb_keyring_read, &cb);
+
+ if (armour) {
+ pgp_reader_push_dearmour(stream);
+ }
+ res = pgp_parse_and_accumulate(keyring, stream);
+ pgp_print_errors(pgp_stream_get_errors(stream));
+
+ if (armour) {
+ pgp_reader_pop_dearmour(stream);
+ }
+
+ (void)close(fd);
+
+ pgp_stream_delete(stream);
+
+ return res;
+}
+
+/**
+ \ingroup HighLevel_KeyringRead
+
+ \brief Reads a keyring from memory
+
+ \param keyring Pointer to existing pgp_keyring_t struct
+ \param armour 1 if file is armoured; else 0
+ \param mem Pointer to a pgp_memory_t struct containing keyring to be read
+
+ \return pgp 1 if OK; 0 on error
+
+ \note Keyring struct must already exist.
+
+ \note Can be used with either a public or secret keyring.
+
+ \note You must call pgp_keyring_free() after usage to free alloc-ed memory.
+
+ \note If you call this twice on the same keyring struct, without calling
+ pgp_keyring_free() between these calls, you will introduce a memory leak.
+
+ \sa pgp_keyring_fileread
+ \sa pgp_keyring_free
+*/
+unsigned
+pgp_keyring_read_from_mem(pgp_io_t *io,
+ pgp_keyring_t *keyring,
+ const unsigned armour,
+ pgp_memory_t *mem)
+{
+ pgp_stream_t *stream;
+ const unsigned noaccum = 0;
+ keyringcb_t cb;
+ unsigned res;
+
+ (void) memset(&cb, 0x0, sizeof(cb));
+ cb.keyring = keyring;
+ stream = pgp_new(sizeof(*stream));
+ pgp_parse_options(stream, PGP_PTAG_SS_ALL, PGP_PARSE_PARSED);
+ pgp_setup_memory_read(io, &stream, mem, &cb, cb_keyring_read,
+ noaccum);
+ if (armour) {
+ pgp_reader_push_dearmour(stream);
+ }
+ res = (unsigned)pgp_parse_and_accumulate(keyring, stream);
+ pgp_print_errors(pgp_stream_get_errors(stream));
+ if (armour) {
+ pgp_reader_pop_dearmour(stream);
+ }
+ /* don't call teardown_memory_read because memory was passed in */
+ pgp_stream_delete(stream);
+ return res;
+}
+
+/**
+ \ingroup HighLevel_KeyringRead
+
+ \brief Frees keyring's contents (but not keyring itself)
+
+ \param keyring Keyring whose data is to be freed
+
+ \note This does not free keyring itself, just the memory alloc-ed in it.
+ */
+void
+pgp_keyring_free(pgp_keyring_t *keyring)
+{
+ (void)free(keyring->keys);
+ keyring->keys = NULL;
+ keyring->keyc = keyring->keyvsize = 0;
+}
+
+/**
+ \ingroup HighLevel_KeyringFind
+
+ \brief Finds key in keyring from its Key ID
+
+ \param keyring Keyring to be searched
+ \param keyid ID of required key
+
+ \return Pointer to key, if found; NULL, if not found
+
+ \note This returns a pointer to the key inside the given keyring,
+ not a copy. Do not free it after use.
+
+*/
+const pgp_key_t *
+pgp_getkeybyid(pgp_io_t *io, const pgp_keyring_t *keyring,
+ const uint8_t *keyid, unsigned *from, pgp_pubkey_t **pubkey)
+{
+ uint8_t nullid[PGP_KEY_ID_SIZE];
+
+ (void) memset(nullid, 0x0, sizeof(nullid));
+ for ( ; keyring && *from < keyring->keyc; *from += 1) {
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(io->errs, "keyring keyid", keyring->keys[*from].sigid, PGP_KEY_ID_SIZE);
+ hexdump(io->errs, "keyid", keyid, PGP_KEY_ID_SIZE);
+ }
+ if (memcmp(keyring->keys[*from].sigid, keyid, PGP_KEY_ID_SIZE) == 0 ||
+ memcmp(&keyring->keys[*from].sigid[PGP_KEY_ID_SIZE / 2],
+ keyid, PGP_KEY_ID_SIZE / 2) == 0) {
+ if (pubkey) {
+ *pubkey = &keyring->keys[*from].key.pubkey;
+ }
+ return &keyring->keys[*from];
+ }
+ if (memcmp(&keyring->keys[*from].encid, nullid, sizeof(nullid)) == 0) {
+ continue;
+ }
+ if (memcmp(&keyring->keys[*from].encid, keyid, PGP_KEY_ID_SIZE) == 0 ||
+ memcmp(&keyring->keys[*from].encid[PGP_KEY_ID_SIZE / 2], keyid, PGP_KEY_ID_SIZE / 2) == 0) {
+ if (pubkey) {
+ *pubkey = &keyring->keys[*from].enckey;
+ }
+ return &keyring->keys[*from];
+ }
+ }
+ return NULL;
+}
+
+/* convert a string keyid into a binary keyid */
+static void
+str2keyid(const char *userid, uint8_t *keyid, size_t len)
+{
+ static const char *uppers = "0123456789ABCDEF";
+ static const char *lowers = "0123456789abcdef";
+ const char *hi;
+ const char *lo;
+ uint8_t hichar;
+ uint8_t lochar;
+ size_t j;
+ int i;
+
+ for (i = 0, j = 0 ; j < len && userid[i] && userid[i + 1] ; i += 2, j++) {
+ if ((hi = strchr(uppers, userid[i])) == NULL) {
+ if ((hi = strchr(lowers, userid[i])) == NULL) {
+ break;
+ }
+ hichar = (uint8_t)(hi - lowers);
+ } else {
+ hichar = (uint8_t)(hi - uppers);
+ }
+ if ((lo = strchr(uppers, userid[i + 1])) == NULL) {
+ if ((lo = strchr(lowers, userid[i + 1])) == NULL) {
+ break;
+ }
+ lochar = (uint8_t)(lo - lowers);
+ } else {
+ lochar = (uint8_t)(lo - uppers);
+ }
+ keyid[j] = (hichar << 4) | (lochar);
+ }
+ keyid[j] = 0x0;
+}
+
+/* return the next key which matches, starting searching at *from */
+static const pgp_key_t *
+getkeybyname(pgp_io_t *io,
+ const pgp_keyring_t *keyring,
+ const char *name,
+ unsigned *from)
+{
+ const pgp_key_t *kp;
+ uint8_t **uidp;
+ unsigned i = 0;
+ pgp_key_t *keyp;
+ unsigned savedstart;
+ regex_t r;
+ uint8_t keyid[PGP_KEY_ID_SIZE + 1];
+ size_t len;
+
+ if (!keyring || !name || !from) {
+ return NULL;
+ }
+ len = strlen(name);
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(io->outs, "[%u] name '%s', len %zu\n",
+ *from, name, len);
+ }
+ /* first try name as a keyid */
+ (void) memset(keyid, 0x0, sizeof(keyid));
+ str2keyid(name, keyid, sizeof(keyid));
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(io->outs, "keyid", keyid, 4);
+ }
+ savedstart = *from;
+ if ((kp = pgp_getkeybyid(io, keyring, keyid, from, NULL)) != NULL) {
+ return kp;
+ }
+ *from = savedstart;
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(io->outs, "regex match '%s' from %u\n",
+ name, *from);
+ }
+ /* match on full name or email address as a NOSUB, ICASE regexp */
+ (void) regcomp(&r, name, REG_EXTENDED | REG_ICASE);
+ for (keyp = &keyring->keys[*from]; *from < keyring->keyc; *from += 1, keyp++) {
+ uidp = keyp->uids;
+ for (i = 0 ; i < keyp->uidc; i++, uidp++) {
+ if (regexec(&r, (char *)*uidp, 0, NULL, 0) == 0) {
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(io->outs,
+ "MATCHED keyid \"%s\" len %" PRIsize "u\n",
+ (char *) *uidp, len);
+ }
+ regfree(&r);
+ return keyp;
+ }
+ }
+ }
+ regfree(&r);
+ return NULL;
+}
+
+/**
+ \ingroup HighLevel_KeyringFind
+
+ \brief Finds key from its User ID
+
+ \param keyring Keyring to be searched
+ \param userid User ID of required key
+
+ \return Pointer to Key, if found; NULL, if not found
+
+ \note This returns a pointer to the key inside the keyring, not a
+ copy. Do not free it.
+
+*/
+const pgp_key_t *
+pgp_getkeybyname(pgp_io_t *io,
+ const pgp_keyring_t *keyring,
+ const char *name)
+{
+ unsigned from;
+
+ from = 0;
+ return getkeybyname(io, keyring, name, &from);
+}
+
+const pgp_key_t *
+pgp_getnextkeybyname(pgp_io_t *io,
+ const pgp_keyring_t *keyring,
+ const char *name,
+ unsigned *n)
+{
+ return getkeybyname(io, keyring, name, n);
+}
+
+/**
+ \ingroup HighLevel_KeyringList
+
+ \brief Prints all keys in keyring to stdout.
+
+ \param keyring Keyring to use
+
+ \return none
+*/
+int
+pgp_keyring_list(pgp_io_t *io, const pgp_keyring_t *keyring, const int psigs)
+{
+ pgp_key_t *key;
+ unsigned n;
+
+ (void) fprintf(io->res, "%u key%s\n", keyring->keyc,
+ (keyring->keyc == 1) ? "" : "s");
+ for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) {
+ if (pgp_is_key_secret(key)) {
+ pgp_print_keydata(io, keyring, key, "sec",
+ &key->key.seckey.pubkey, 0);
+ } else {
+ pgp_print_keydata(io, keyring, key, "signature ", &key->key.pubkey, psigs);
+ }
+ (void) fputc('\n', io->res);
+ }
+ return 1;
+}
+
+int
+pgp_keyring_json(pgp_io_t *io, const pgp_keyring_t *keyring, mj_t *obj, const int psigs)
+{
+ pgp_key_t *key;
+ unsigned n;
+
+ (void) memset(obj, 0x0, sizeof(*obj));
+ mj_create(obj, "array");
+ obj->size = keyring->keyvsize;
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(io->errs, "pgp_keyring_json: vsize %u\n", obj->size);
+ }
+ if ((obj->value.v = calloc(sizeof(*obj->value.v), obj->size)) == NULL) {
+ (void) fprintf(io->errs, "calloc failure\n");
+ return 0;
+ }
+ for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) {
+ if (pgp_is_key_secret(key)) {
+ pgp_sprint_mj(io, keyring, key, &obj->value.v[obj->c],
+ "sec", &key->key.seckey.pubkey, psigs);
+ } else {
+ pgp_sprint_mj(io, keyring, key, &obj->value.v[obj->c],
+ "signature ", &key->key.pubkey, psigs);
+ }
+ if (obj->value.v[obj->c].type != 0) {
+ obj->c += 1;
+ }
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ char *s;
+
+ mj_asprint(&s, obj, MJ_JSON_ENCODE);
+ (void) fprintf(stderr, "pgp_keyring_json: '%s'\n", s);
+ free(s);
+ }
+ return 1;
+}
+
+
+/* this interface isn't right - hook into callback for getting passphrase */
+char *
+pgp_export_key(pgp_io_t *io, const pgp_key_t *keydata, uint8_t *passphrase)
+{
+ pgp_output_t *output;
+ pgp_memory_t *mem;
+ char *cp;
+
+ __PGP_USED(io);
+ pgp_setup_memory_write(&output, &mem, 128);
+ if (keydata->type == PGP_PTAG_CT_PUBLIC_KEY) {
+ pgp_write_xfer_pubkey(output, keydata, 1);
+ } else {
+ pgp_write_xfer_seckey(output, keydata, passphrase,
+ strlen((char *)passphrase), 1);
+ }
+ cp = netpgp_strdup(pgp_mem_data(mem));
+ pgp_teardown_memory_write(output, mem);
+ return cp;
+}
+
+/* add a key to a public keyring */
+int
+pgp_add_to_pubring(pgp_keyring_t *keyring, const pgp_pubkey_t *pubkey, pgp_content_enum tag)
+{
+ pgp_key_t *key;
+ time_t duration;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "pgp_add_to_pubring (type %u)\n", tag);
+ }
+ switch(tag) {
+ case PGP_PTAG_CT_PUBLIC_KEY:
+ EXPAND_ARRAY(keyring, key);
+ key = &keyring->keys[keyring->keyc++];
+ duration = key->key.pubkey.duration;
+ (void) memset(key, 0x0, sizeof(*key));
+ key->type = tag;
+ pgp_keyid(key->sigid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
+ pgp_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype);
+ key->key.pubkey = *pubkey;
+ key->key.pubkey.duration = duration;
+ return 1;
+ case PGP_PTAG_CT_PUBLIC_SUBKEY:
+ /* subkey is not the first */
+ key = &keyring->keys[keyring->keyc - 1];
+ pgp_keyid(key->encid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
+ duration = key->key.pubkey.duration;
+ (void) memcpy(&key->enckey, pubkey, sizeof(key->enckey));
+ key->enckey.duration = duration;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* add a key to a secret keyring */
+int
+pgp_add_to_secring(pgp_keyring_t *keyring, const pgp_seckey_t *seckey)
+{
+ const pgp_pubkey_t *pubkey;
+ pgp_key_t *key;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "pgp_add_to_secring\n");
+ }
+ if (keyring->keyc > 0) {
+ key = &keyring->keys[keyring->keyc - 1];
+ if (pgp_get_debug_level(__FILE__) &&
+ key->key.pubkey.alg == PGP_PKA_DSA &&
+ seckey->pubkey.alg == PGP_PKA_ELGAMAL) {
+ fprintf(stderr, "pgp_add_to_secring: found elgamal seckey\n");
+ }
+ }
+ EXPAND_ARRAY(keyring, key);
+ key = &keyring->keys[keyring->keyc++];
+ (void) memset(key, 0x0, sizeof(*key));
+ pubkey = &seckey->pubkey;
+ pgp_keyid(key->sigid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
+ pgp_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype);
+ key->type = PGP_PTAG_CT_SECRET_KEY;
+ key->key.seckey = *seckey;
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "pgp_add_to_secring: keyc %u\n", keyring->keyc);
+ }
+ return 1;
+}
+
+/* append one keyring to another */
+int
+pgp_append_keyring(pgp_keyring_t *keyring, pgp_keyring_t *newring)
+{
+ unsigned i;
+
+ for (i = 0 ; i < newring->keyc ; i++) {
+ EXPAND_ARRAY(keyring, key);
+ (void) memcpy(&keyring->keys[keyring->keyc], &newring->keys[i],
+ sizeof(newring->keys[i]));
+ keyring->keyc += 1;
+ }
+ return 1;
+}
diff --git a/libs/netpgp/src/lib/keyring.h b/libs/netpgp/src/lib/keyring.h
new file mode 100644
index 00000000..920ad0f6
--- /dev/null
+++ b/libs/netpgp/src/lib/keyring.h
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+
+#ifndef KEYRING_H_
+#define KEYRING_H_
+
+#include "packet.h"
+#include "packet-parse.h"
+#include "mj.h"
+
+enum {
+ MAX_ID_LENGTH = 128,
+ MAX_PASSPHRASE_LENGTH = 256
+};
+
+typedef struct pgp_key_t pgp_key_t;
+
+/** \struct pgp_keyring_t
+ * A keyring
+ */
+typedef struct pgp_keyring_t {
+ DYNARRAY(pgp_key_t, key);
+ pgp_hash_alg_t hashtype;
+} pgp_keyring_t;
+
+const pgp_key_t *pgp_getkeybyid(pgp_io_t *,
+ const pgp_keyring_t *,
+ const uint8_t *,
+ unsigned *,
+ pgp_pubkey_t **);
+const pgp_key_t *pgp_getkeybyname(pgp_io_t *,
+ const pgp_keyring_t *,
+ const char *);
+const pgp_key_t *pgp_getnextkeybyname(pgp_io_t *,
+ const pgp_keyring_t *,
+ const char *,
+ unsigned *);
+void pgp_keydata_free(pgp_key_t *);
+void pgp_keyring_free(pgp_keyring_t *);
+void pgp_dump_keyring(const pgp_keyring_t *);
+const pgp_pubkey_t *pgp_get_pubkey(const pgp_key_t *);
+unsigned pgp_is_key_secret(const pgp_key_t *);
+const pgp_seckey_t *pgp_get_seckey(const pgp_key_t *);
+pgp_seckey_t *pgp_get_writable_seckey(pgp_key_t *);
+pgp_seckey_t *pgp_decrypt_seckey(const pgp_key_t *, void *);
+
+unsigned pgp_keyring_fileread(pgp_keyring_t *, const unsigned,
+ const char *);
+
+int pgp_keyring_list(pgp_io_t *, const pgp_keyring_t *, const int);
+int pgp_keyring_json(pgp_io_t *, const pgp_keyring_t *, mj_t *, const int);
+
+void pgp_set_seckey(pgp_contents_t *, const pgp_key_t *);
+void pgp_forget(void *, unsigned);
+
+const uint8_t *pgp_get_key_id(const pgp_key_t *);
+unsigned pgp_get_userid_count(const pgp_key_t *);
+const uint8_t *pgp_get_userid(const pgp_key_t *, unsigned);
+unsigned pgp_is_key_supported(const pgp_key_t *);
+
+uint8_t *pgp_add_userid(pgp_key_t *, const uint8_t *);
+pgp_subpacket_t *pgp_add_subpacket(pgp_key_t *,
+ const pgp_subpacket_t *);
+
+unsigned pgp_add_selfsigned_userid(pgp_key_t *, uint8_t *);
+
+pgp_key_t *pgp_keydata_new(void);
+void pgp_keydata_init(pgp_key_t *, const pgp_content_enum);
+
+int pgp_parse_and_accumulate(pgp_keyring_t *, pgp_stream_t *);
+
+int pgp_sprint_keydata(pgp_io_t *, const pgp_keyring_t *,
+ const pgp_key_t *, char **, const char *,
+ const pgp_pubkey_t *, const int);
+int pgp_sprint_mj(pgp_io_t *, const pgp_keyring_t *,
+ const pgp_key_t *, mj_t *, const char *,
+ const pgp_pubkey_t *, const int);
+int pgp_hkp_sprint_keydata(pgp_io_t *, const pgp_keyring_t *,
+ const pgp_key_t *, char **,
+ const pgp_pubkey_t *, const int);
+void pgp_print_keydata(pgp_io_t *, const pgp_keyring_t *, const pgp_key_t *,
+ const char *, const pgp_pubkey_t *, const int);
+void pgp_print_sig(pgp_io_t *, const pgp_key_t *, const char *,
+ const pgp_pubkey_t *);
+void pgp_print_pubkey(const pgp_pubkey_t *);
+int pgp_sprint_pubkey(const pgp_key_t *, char *, size_t);
+
+int pgp_list_packets(pgp_io_t *,
+ char *,
+ unsigned,
+ pgp_keyring_t *,
+ pgp_keyring_t *,
+ void *,
+ pgp_cbfunc_t *);
+
+char *pgp_export_key(pgp_io_t *, const pgp_key_t *, uint8_t *);
+
+int pgp_add_to_pubring(pgp_keyring_t *, const pgp_pubkey_t *, pgp_content_enum tag);
+int pgp_add_to_secring(pgp_keyring_t *, const pgp_seckey_t *);
+
+int pgp_append_keyring(pgp_keyring_t *, pgp_keyring_t *);
+
+#endif /* KEYRING_H_ */
diff --git a/libs/netpgp/src/lib/memory.h b/libs/netpgp/src/lib/memory.h
new file mode 100644
index 00000000..d8bd5763
--- /dev/null
+++ b/libs/netpgp/src/lib/memory.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#ifndef MEMORY_H_
+#define MEMORY_H_
+
+#include
+
+#include "packet.h"
+
+/** pgp_memory_t
+ */
+typedef struct pgp_memory_t {
+ uint8_t *buf;
+ size_t length;
+ size_t allocated;
+ unsigned mmapped;
+} pgp_memory_t;
+
+
+pgp_memory_t *pgp_memory_new(void);
+void pgp_memory_free(pgp_memory_t *);
+void pgp_memory_init(pgp_memory_t *, size_t);
+void pgp_memory_pad(pgp_memory_t *, size_t);
+void pgp_memory_add(pgp_memory_t *, const uint8_t *, size_t);
+void pgp_memory_place_int(pgp_memory_t *, unsigned, unsigned, size_t);
+void pgp_memory_make_packet(pgp_memory_t *, pgp_content_enum);
+void pgp_memory_clear(pgp_memory_t *);
+void pgp_memory_release(pgp_memory_t *);
+
+void pgp_writer_set_memory(pgp_output_t *, pgp_memory_t *);
+
+size_t pgp_mem_len(const pgp_memory_t *);
+void *pgp_mem_data(pgp_memory_t *);
+int pgp_mem_readfile(pgp_memory_t *, const char *);
+
+void pgp_random(void *, size_t);
+
+#endif /* MEMORY_H_ */
diff --git a/libs/netpgp/src/lib/misc.c b/libs/netpgp/src/lib/misc.c
new file mode 100644
index 00000000..705664c6
--- /dev/null
+++ b/libs/netpgp/src/lib/misc.c
@@ -0,0 +1,1354 @@
+/*-
+ * Copyright (c) 2009,2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: misc.c,v 1.41 2012/03/05 02:20:18 christos Exp $");
+#endif
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_RAND_H
+#include
+#endif
+
+#include "errors.h"
+#include "packet.h"
+#include "crypto.h"
+#include "create.h"
+#include "packet-parse.h"
+#include "packet-show.h"
+#include "signature.h"
+#include "netpgpsdk.h"
+#include "netpgpdefs.h"
+#include "memory.h"
+#include "readerwriter.h"
+#include "version.h"
+#include "netpgpdigest.h"
+
+#ifdef WIN32
+#define vsnprintf _vsnprintf
+#endif
+
+
+typedef struct {
+ pgp_keyring_t *keyring;
+} accumulate_t;
+
+/**
+ * \ingroup Core_Callbacks
+ */
+static pgp_cb_ret_t
+accumulate_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+ pgp_keyring_t *keyring;
+ accumulate_t *accumulate;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "accumulate callback: packet tag %u\n", pkt->tag);
+ }
+ accumulate = pgp_callback_arg(cbinfo);
+ keyring = accumulate->keyring;
+ switch (pkt->tag) {
+ case PGP_PTAG_CT_PUBLIC_KEY:
+ case PGP_PTAG_CT_PUBLIC_SUBKEY:
+ pgp_add_to_pubring(keyring, &content->pubkey, pkt->tag);
+ return PGP_KEEP_MEMORY;
+ case PGP_PTAG_CT_SECRET_KEY:
+ case PGP_PTAG_CT_ENCRYPTED_SECRET_KEY:
+ pgp_add_to_secring(keyring, &content->seckey);
+ return PGP_KEEP_MEMORY;
+ case PGP_PTAG_CT_USER_ID:
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "User ID: %s for key %d\n",
+ content->userid,
+ keyring->keyc - 1);
+ }
+ if (keyring->keyc == 0) {
+ PGP_ERROR_1(cbinfo->errors, PGP_E_P_NO_USERID, "%s",
+ "No userid found");
+ } else {
+ pgp_add_userid(&keyring->keys[keyring->keyc - 1], content->userid);
+ }
+ return PGP_KEEP_MEMORY;
+ case PGP_PARSER_PACKET_END:
+ if (keyring->keyc > 0) {
+ pgp_add_subpacket(&keyring->keys[keyring->keyc - 1],
+ &content->packet);
+ return PGP_KEEP_MEMORY;
+ }
+ return PGP_RELEASE_MEMORY;
+ case PGP_PARSER_ERROR:
+ (void) fprintf(stderr, "Error: %s\n", content->error);
+ return PGP_FINISHED;
+ case PGP_PARSER_ERRCODE:
+ (void) fprintf(stderr, "parse error: %s\n",
+ pgp_errcode(content->errcode.errcode));
+ break;
+ default:
+ break;
+ }
+ /* XXX: we now exclude so many things, we should either drop this or */
+ /* do something to pass on copies of the stuff we keep */
+ return pgp_stacked_callback(pkt, cbinfo);
+}
+
+/**
+ * \ingroup Core_Parse
+ *
+ * Parse packets from an input stream until EOF or error.
+ *
+ * Key data found in the parsed data is added to #keyring.
+ *
+ * \param keyring Pointer to an existing keyring
+ * \param parse Options to use when parsing
+*/
+int
+pgp_parse_and_accumulate(pgp_keyring_t *keyring, pgp_stream_t *parse)
+{
+ accumulate_t accumulate;
+ const int printerrors = 1;
+ int ret;
+
+ if (parse->readinfo.accumulate) {
+ (void) fprintf(stderr,
+ "pgp_parse_and_accumulate: already init\n");
+ return 0;
+ }
+
+ (void) memset(&accumulate, 0x0, sizeof(accumulate));
+
+ accumulate.keyring = keyring;
+
+ pgp_callback_push(parse, accumulate_cb, &accumulate);
+ parse->readinfo.accumulate = 1;
+ ret = pgp_parse(parse, !printerrors);
+
+ return ret;
+}
+
+
+/** \file
+ * \brief Error Handling
+ */
+#define ERRNAME(code) { code, #code }
+
+static pgp_errcode_name_map_t errcode_name_map[] = {
+ ERRNAME(PGP_E_OK),
+ ERRNAME(PGP_E_FAIL),
+ ERRNAME(PGP_E_SYSTEM_ERROR),
+ ERRNAME(PGP_E_UNIMPLEMENTED),
+
+ ERRNAME(PGP_E_R),
+ ERRNAME(PGP_E_R_READ_FAILED),
+ ERRNAME(PGP_E_R_EARLY_EOF),
+ ERRNAME(PGP_E_R_BAD_FORMAT),
+ ERRNAME(PGP_E_R_UNCONSUMED_DATA),
+
+ ERRNAME(PGP_E_W),
+ ERRNAME(PGP_E_W_WRITE_FAILED),
+ ERRNAME(PGP_E_W_WRITE_TOO_SHORT),
+
+ ERRNAME(PGP_E_P),
+ ERRNAME(PGP_E_P_NOT_ENOUGH_DATA),
+ ERRNAME(PGP_E_P_UNKNOWN_TAG),
+ ERRNAME(PGP_E_P_PACKET_CONSUMED),
+ ERRNAME(PGP_E_P_MPI_FORMAT_ERROR),
+
+ ERRNAME(PGP_E_C),
+
+ ERRNAME(PGP_E_V),
+ ERRNAME(PGP_E_V_BAD_SIGNATURE),
+ ERRNAME(PGP_E_V_NO_SIGNATURE),
+ ERRNAME(PGP_E_V_UNKNOWN_SIGNER),
+
+ ERRNAME(PGP_E_ALG),
+ ERRNAME(PGP_E_ALG_UNSUPPORTED_SYMMETRIC_ALG),
+ ERRNAME(PGP_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG),
+ ERRNAME(PGP_E_ALG_UNSUPPORTED_SIGNATURE_ALG),
+ ERRNAME(PGP_E_ALG_UNSUPPORTED_HASH_ALG),
+
+ ERRNAME(PGP_E_PROTO),
+ ERRNAME(PGP_E_PROTO_BAD_SYMMETRIC_DECRYPT),
+ ERRNAME(PGP_E_PROTO_UNKNOWN_SS),
+ ERRNAME(PGP_E_PROTO_CRITICAL_SS_IGNORED),
+ ERRNAME(PGP_E_PROTO_BAD_PUBLIC_KEY_VRSN),
+ ERRNAME(PGP_E_PROTO_BAD_SIGNATURE_VRSN),
+ ERRNAME(PGP_E_PROTO_BAD_ONE_PASS_SIG_VRSN),
+ ERRNAME(PGP_E_PROTO_BAD_PKSK_VRSN),
+ ERRNAME(PGP_E_PROTO_DECRYPTED_MSG_WRONG_LEN),
+ ERRNAME(PGP_E_PROTO_BAD_SK_CHECKSUM),
+
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+/**
+ * \ingroup Core_Errors
+ * \brief returns error code name
+ * \param errcode
+ * \return error code name or "Unknown"
+ */
+const char *
+pgp_errcode(const pgp_errcode_t errcode)
+{
+ return (pgp_str_from_map((int) errcode,
+ (pgp_map_t *) errcode_name_map));
+}
+
+/* generic grab new storage function */
+void *
+pgp_new(size_t size)
+{
+ void *vp;
+
+ if ((vp = calloc(1, size)) == NULL) {
+ (void) fprintf(stderr,
+ "allocation failure for %" PRIsize "u bytes", size);
+ }
+ return vp;
+}
+
+/**
+ * \ingroup Core_Errors
+ * \brief Pushes the given error on the given errorstack
+ * \param errstack Error stack to use
+ * \param errcode Code of error to push
+ * \param sys_errno System errno (used if errcode=PGP_E_SYSTEM_ERROR)
+ * \param file Source filename where error occurred
+ * \param line Line in source file where error occurred
+ * \param fmt Comment
+ *
+ */
+
+void
+pgp_push_error(pgp_error_t **errstack, pgp_errcode_t errcode,
+ int sys_errno, const char *file, int line, const char *fmt,...)
+{
+ /* first get the varargs and generate the comment */
+ pgp_error_t *err;
+ unsigned maxbuf = 128;
+ va_list args;
+ char *comment;
+
+ if ((comment = calloc(1, maxbuf + 1)) == NULL) {
+ (void) fprintf(stderr, "calloc comment failure\n");
+ return;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(comment, maxbuf + 1, fmt, args);
+ va_end(args);
+
+ /* alloc a new error and add it to the top of the stack */
+
+ if ((err = calloc(1, sizeof(*err))) == NULL) {
+ (void) fprintf(stderr, "calloc comment failure\n");
+ return;
+ }
+
+ err->next = *errstack;
+ *errstack = err;
+
+ /* fill in the details */
+ err->errcode = errcode;
+ err->sys_errno = sys_errno;
+ err->file = file;
+ err->line = line;
+
+ err->comment = comment;
+}
+
+/**
+\ingroup Core_Errors
+\brief print this error
+\param err Error to print
+*/
+void
+pgp_print_error(pgp_error_t *err)
+{
+ printf("%s:%d: ", err->file, err->line);
+ if (err->errcode == PGP_E_SYSTEM_ERROR) {
+ printf("system error %d returned from %s()\n", err->sys_errno,
+ err->comment);
+ } else {
+ printf("%s, %s\n", pgp_errcode(err->errcode), err->comment);
+ }
+}
+
+/**
+\ingroup Core_Errors
+\brief Print all errors on stack
+\param errstack Error stack to print
+*/
+void
+pgp_print_errors(pgp_error_t *errstack)
+{
+ pgp_error_t *err;
+
+ for (err = errstack; err != NULL; err = err->next) {
+ pgp_print_error(err);
+ }
+}
+
+/**
+\ingroup Core_Errors
+\brief Return 1 if given error is present anywhere on stack
+\param errstack Error stack to check
+\param errcode Error code to look for
+\return 1 if found; else 0
+*/
+int
+pgp_has_error(pgp_error_t *errstack, pgp_errcode_t errcode)
+{
+ pgp_error_t *err;
+
+ for (err = errstack; err != NULL; err = err->next) {
+ if (err->errcode == errcode) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+\ingroup Core_Errors
+\brief Frees all errors on stack
+\param errstack Error stack to free
+*/
+void
+pgp_free_errors(pgp_error_t *errstack)
+{
+ pgp_error_t *next;
+
+ while (errstack != NULL) {
+ next = errstack->next;
+ free(errstack->comment);
+ free(errstack);
+ errstack = next;
+ }
+}
+
+/* hash a 32-bit integer */
+static int
+hash_uint32(pgp_hash_t *hash, uint32_t n)
+{
+ uint8_t ibuf[4];
+
+ ibuf[0] = (uint8_t)(n >> 24) & 0xff;
+ ibuf[1] = (uint8_t)(n >> 16) & 0xff;
+ ibuf[2] = (uint8_t)(n >> 8) & 0xff;
+ ibuf[3] = (uint8_t)n & 0xff;
+ (*hash->add)(hash, (const uint8_t *)(void *)ibuf, (unsigned)sizeof(ibuf));
+ return sizeof(ibuf);
+}
+
+/* hash a string - first length, then string itself */
+static int
+hash_string(pgp_hash_t *hash, const uint8_t *buf, uint32_t len)
+{
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "hash_string", buf, len);
+ }
+ hash_uint32(hash, len);
+ (*hash->add)(hash, buf, len);
+ return (int)(sizeof(len) + len);
+}
+
+/* hash a bignum, possibly padded - first length, then string itself */
+static int
+hash_bignum(pgp_hash_t *hash, BIGNUM *bignum)
+{
+ uint8_t *bn;
+ size_t len;
+ int padbyte;
+
+ if (BN_is_zero(bignum)) {
+ hash_uint32(hash, 0);
+ return sizeof(len);
+ }
+ if ((len = (size_t) BN_num_bytes(bignum)) < 1) {
+ (void) fprintf(stderr, "hash_bignum: bad size\n");
+ return 0;
+ }
+ if ((bn = calloc(1, len)) == NULL) {
+ (void) fprintf(stderr, "hash_bignum: bad bn alloc\n");
+ return 0;
+ }
+ BN_bn2bin(bignum, bn + 1);
+ bn[0] = 0x0;
+ padbyte = (bn[1] & 0x80) ? 1 : 0;
+ hash_string(hash, bn + 1 - padbyte, (unsigned)(len + padbyte));
+ free(bn);
+ return (int)(sizeof(len) + len + padbyte);
+}
+
+/** \file
+ */
+
+/**
+ * \ingroup Core_Keys
+ * \brief Calculate a public key fingerprint.
+ * \param fp Where to put the calculated fingerprint
+ * \param key The key for which the fingerprint is calculated
+ */
+int
+pgp_fingerprint(pgp_fingerprint_t *fp, const pgp_pubkey_t *key, pgp_hash_alg_t hashtype)
+{
+ pgp_memory_t *mem;
+ pgp_hash_t hash;
+ const char *type;
+ uint32_t len;
+
+ mem = pgp_memory_new();
+ if (key->version == 2 || key->version == 3) {
+ if (key->alg != PGP_PKA_RSA &&
+ key->alg != PGP_PKA_RSA_ENCRYPT_ONLY &&
+ key->alg != PGP_PKA_RSA_SIGN_ONLY) {
+ (void) fprintf(stderr,
+ "pgp_fingerprint: bad algorithm\n");
+ return 0;
+ }
+ pgp_hash_md5(&hash);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr,
+ "pgp_fingerprint: bad md5 alloc\n");
+ return 0;
+ }
+ hash_bignum(&hash, key->key.rsa.n);
+ hash_bignum(&hash, key->key.rsa.e);
+ fp->length = hash.finish(&hash, fp->fingerprint);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "v2/v3 fingerprint", fp->fingerprint, fp->length);
+ }
+ } else if (hashtype == PGP_HASH_MD5) {
+ pgp_hash_md5(&hash);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr,
+ "pgp_fingerprint: bad md5 alloc\n");
+ return 0;
+ }
+ type = (key->alg == PGP_PKA_RSA) ? "ssh-rsa" : "ssh-dss";
+ hash_string(&hash, (const uint8_t *)(const void *)type, (unsigned)strlen(type));
+ switch(key->alg) {
+ case PGP_PKA_RSA:
+ hash_bignum(&hash, key->key.rsa.e);
+ hash_bignum(&hash, key->key.rsa.n);
+ break;
+ case PGP_PKA_DSA:
+ hash_bignum(&hash, key->key.dsa.p);
+ hash_bignum(&hash, key->key.dsa.q);
+ hash_bignum(&hash, key->key.dsa.g);
+ hash_bignum(&hash, key->key.dsa.y);
+ break;
+ default:
+ break;
+ }
+ fp->length = hash.finish(&hash, fp->fingerprint);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "md5 fingerprint", fp->fingerprint, fp->length);
+ }
+ } else {
+ pgp_build_pubkey(mem, key, 0);
+ pgp_hash_sha1(&hash);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr,
+ "pgp_fingerprint: bad sha1 alloc\n");
+ return 0;
+ }
+ len = (unsigned)pgp_mem_len(mem);
+ pgp_hash_add_int(&hash, 0x99, 1);
+ pgp_hash_add_int(&hash, len, 2);
+ hash.add(&hash, pgp_mem_data(mem), len);
+ fp->length = hash.finish(&hash, fp->fingerprint);
+ pgp_memory_free(mem);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha1 fingerprint", fp->fingerprint, fp->length);
+ }
+ }
+ return 1;
+}
+
+/**
+ * \ingroup Core_Keys
+ * \brief Calculate the Key ID from the public key.
+ * \param keyid Space for the calculated ID to be stored
+ * \param key The key for which the ID is calculated
+ */
+
+int
+pgp_keyid(uint8_t *keyid, const size_t idlen, const pgp_pubkey_t *key, pgp_hash_alg_t hashtype)
+{
+ pgp_fingerprint_t finger;
+
+ if (key->version == 2 || key->version == 3) {
+ unsigned n;
+ uint8_t bn[NETPGP_BUFSIZ];
+
+ n = (unsigned) BN_num_bytes(key->key.rsa.n);
+ if (n > sizeof(bn)) {
+ (void) fprintf(stderr, "pgp_keyid: bad num bytes\n");
+ return 0;
+ }
+ if (key->alg != PGP_PKA_RSA &&
+ key->alg != PGP_PKA_RSA_ENCRYPT_ONLY &&
+ key->alg != PGP_PKA_RSA_SIGN_ONLY) {
+ (void) fprintf(stderr, "pgp_keyid: bad algorithm\n");
+ return 0;
+ }
+ BN_bn2bin(key->key.rsa.n, bn);
+ (void) memcpy(keyid, bn + n - idlen, idlen);
+ } else {
+ pgp_fingerprint(&finger, key, hashtype);
+ (void) memcpy(keyid,
+ finger.fingerprint + finger.length - idlen,
+ idlen);
+ }
+ return 1;
+}
+
+/**
+\ingroup Core_Hashes
+\brief Add to the hash
+\param hash Hash to add to
+\param n Int to add
+\param length Length of int in bytes
+*/
+void
+pgp_hash_add_int(pgp_hash_t *hash, unsigned n, unsigned length)
+{
+ uint8_t c;
+
+ while (length--) {
+ c = n >> (length * 8);
+ hash->add(hash, &c, 1);
+ }
+}
+
+/**
+\ingroup Core_Hashes
+\brief Setup hash for given hash algorithm
+\param hash Hash to set up
+\param alg Hash algorithm to use
+*/
+void
+pgp_hash_any(pgp_hash_t *hash, pgp_hash_alg_t alg)
+{
+ switch (alg) {
+ case PGP_HASH_MD5:
+ pgp_hash_md5(hash);
+ break;
+
+ case PGP_HASH_SHA1:
+ pgp_hash_sha1(hash);
+ break;
+
+ case PGP_HASH_SHA256:
+ pgp_hash_sha256(hash);
+ break;
+
+ case PGP_HASH_SHA384:
+ pgp_hash_sha384(hash);
+ break;
+
+ case PGP_HASH_SHA512:
+ pgp_hash_sha512(hash);
+ break;
+
+ case PGP_HASH_SHA224:
+ pgp_hash_sha224(hash);
+ break;
+
+ default:
+ (void) fprintf(stderr, "pgp_hash_any: bad algorithm\n");
+ }
+}
+
+/**
+\ingroup Core_Hashes
+\brief Returns size of hash for given hash algorithm
+\param alg Hash algorithm to use
+\return Size of hash algorithm in bytes
+*/
+unsigned
+pgp_hash_size(pgp_hash_alg_t alg)
+{
+ switch (alg) {
+ case PGP_HASH_MD5:
+ return 16;
+
+ case PGP_HASH_SHA1:
+ return 20;
+
+ case PGP_HASH_SHA256:
+ return 32;
+
+ case PGP_HASH_SHA224:
+ return 28;
+
+ case PGP_HASH_SHA512:
+ return 64;
+
+ case PGP_HASH_SHA384:
+ return 48;
+
+ default:
+ (void) fprintf(stderr, "pgp_hash_size: bad algorithm\n");
+ }
+
+ return 0;
+}
+
+/**
+\ingroup Core_Hashes
+\brief Returns hash enum corresponding to given string
+\param hash Text name of hash algorithm i.e. "SHA1"
+\returns Corresponding enum i.e. PGP_HASH_SHA1
+*/
+pgp_hash_alg_t
+pgp_str_to_hash_alg(const char *hash)
+{
+ if (hash == NULL) {
+ return PGP_DEFAULT_HASH_ALGORITHM;
+ }
+ if (netpgp_strcasecmp(hash, "SHA1") == 0) {
+ return PGP_HASH_SHA1;
+ }
+ if (netpgp_strcasecmp(hash, "MD5") == 0) {
+ return PGP_HASH_MD5;
+ }
+ if (netpgp_strcasecmp(hash, "SHA256") == 0) {
+ return PGP_HASH_SHA256;
+ }
+ /*
+ if (netpgp_strcasecmp(hash,"SHA224") == 0) {
+ return PGP_HASH_SHA224;
+ }
+ */
+ if (netpgp_strcasecmp(hash, "SHA512") == 0) {
+ return PGP_HASH_SHA512;
+ }
+ if (netpgp_strcasecmp(hash, "SHA384") == 0) {
+ return PGP_HASH_SHA384;
+ }
+ return PGP_HASH_UNKNOWN;
+}
+
+/**
+\ingroup Core_Hashes
+\brief Hash given data
+\param out Where to write the hash
+\param alg Hash algorithm to use
+\param in Data to hash
+\param length Length of data
+\return Size of hash created
+*/
+unsigned
+pgp_hash(uint8_t *out, pgp_hash_alg_t alg, const void *in, size_t length)
+{
+ pgp_hash_t hash;
+
+ pgp_hash_any(&hash, alg);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr, "pgp_hash: bad alloc\n");
+ /* we'll just continue here - don't want to return a 0 hash */
+ /* XXX - agc - no way to return failure */
+ }
+ hash.add(&hash, in, (unsigned)length);
+ return hash.finish(&hash, out);
+}
+
+/**
+\ingroup Core_Hashes
+\brief Calculate hash for MDC packet
+\param preamble Preamble to hash
+\param sz_preamble Size of preamble
+\param plaintext Plaintext to hash
+\param sz_plaintext Size of plaintext
+\param hashed Resulting hash
+*/
+void
+pgp_calc_mdc_hash(const uint8_t *preamble,
+ const size_t sz_preamble,
+ const uint8_t *plaintext,
+ const unsigned sz_plaintext,
+ uint8_t *hashed)
+{
+ pgp_hash_t hash;
+ uint8_t c;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "preamble", preamble, sz_preamble);
+ hexdump(stderr, "plaintext", plaintext, sz_plaintext);
+ }
+ /* init */
+ pgp_hash_any(&hash, PGP_HASH_SHA1);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr, "pgp_calc_mdc_hash: bad alloc\n");
+ /* we'll just continue here - it will die anyway */
+ /* agc - XXX - no way to return failure */
+ }
+
+ /* preamble */
+ hash.add(&hash, preamble, (unsigned)sz_preamble);
+ /* plaintext */
+ hash.add(&hash, plaintext, sz_plaintext);
+ /* MDC packet tag */
+ c = MDC_PKT_TAG;
+ hash.add(&hash, &c, 1);
+ /* MDC packet len */
+ c = PGP_SHA1_HASH_SIZE;
+ hash.add(&hash, &c, 1);
+
+ /* finish */
+ hash.finish(&hash, hashed);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "hashed", hashed, PGP_SHA1_HASH_SIZE);
+ }
+}
+
+/**
+\ingroup HighLevel_Supported
+\brief Is this Hash Algorithm supported?
+\param hash_alg Hash Algorithm to check
+\return 1 if supported; else 0
+*/
+unsigned
+pgp_is_hash_alg_supported(const pgp_hash_alg_t *hash_alg)
+{
+ switch (*hash_alg) {
+ case PGP_HASH_MD5:
+ case PGP_HASH_SHA1:
+ case PGP_HASH_SHA256:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* structure to map string to cipher def */
+typedef struct str2cipher_t {
+ const char *s; /* cipher name */
+ pgp_symm_alg_t i; /* cipher def */
+} str2cipher_t;
+
+static str2cipher_t str2cipher[] = {
+ { "cast5", PGP_SA_CAST5 },
+ { "idea", PGP_SA_IDEA },
+ { "aes128", PGP_SA_AES_128 },
+ { "aes256", PGP_SA_AES_256 },
+ { "camellia128", PGP_SA_CAMELLIA_128 },
+ { "camellia256", PGP_SA_CAMELLIA_256 },
+ { "tripledes", PGP_SA_TRIPLEDES },
+ { NULL, 0 }
+};
+
+/* convert from a string to a cipher definition */
+pgp_symm_alg_t
+pgp_str_to_cipher(const char *cipher)
+{
+ str2cipher_t *sp;
+
+ for (sp = str2cipher ; cipher && sp->s ; sp++) {
+ if (netpgp_strcasecmp(cipher, sp->s) == 0) {
+ return sp->i;
+ }
+ }
+ return PGP_SA_DEFAULT_CIPHER;
+}
+
+void
+pgp_random(void *dest, size_t length)
+{
+ RAND_bytes(dest, (int)length);
+}
+
+/**
+\ingroup HighLevel_Memory
+\brief Memory to initialise
+\param mem memory to initialise
+\param needed Size to initialise to
+*/
+void
+pgp_memory_init(pgp_memory_t *mem, size_t needed)
+{
+ uint8_t *temp;
+
+ mem->length = 0;
+ if (mem->buf) {
+ if (mem->allocated < needed) {
+ if ((temp = realloc(mem->buf, needed)) == NULL) {
+ (void) fprintf(stderr, "pgp_memory_init: bad alloc\n");
+ } else {
+ mem->buf = temp;
+ mem->allocated = needed;
+ }
+ }
+ } else {
+ if ((mem->buf = calloc(1, needed)) == NULL) {
+ (void) fprintf(stderr, "pgp_memory_init: bad alloc\n");
+ } else {
+ mem->allocated = needed;
+ }
+ }
+}
+
+/**
+\ingroup HighLevel_Memory
+\brief Pad memory to required length
+\param mem Memory to use
+\param length New size
+*/
+void
+pgp_memory_pad(pgp_memory_t *mem, size_t length)
+{
+ uint8_t *temp;
+
+ if (mem->allocated < mem->length) {
+ (void) fprintf(stderr, "pgp_memory_pad: bad alloc in\n");
+ return;
+ }
+ if (mem->allocated < mem->length + length) {
+ mem->allocated = mem->allocated * 2 + length;
+ temp = realloc(mem->buf, mem->allocated);
+ if (temp == NULL) {
+ (void) fprintf(stderr, "pgp_memory_pad: bad alloc\n");
+ } else {
+ mem->buf = temp;
+ }
+ }
+ if (mem->allocated < mem->length + length) {
+ (void) fprintf(stderr, "pgp_memory_pad: bad alloc out\n");
+ }
+}
+
+/**
+\ingroup HighLevel_Memory
+\brief Add data to memory
+\param mem Memory to which to add
+\param src Data to add
+\param length Length of data to add
+*/
+void
+pgp_memory_add(pgp_memory_t *mem, const uint8_t *src, size_t length)
+{
+ pgp_memory_pad(mem, length);
+ (void) memcpy(mem->buf + mem->length, src, length);
+ mem->length += length;
+}
+
+/* XXX: this could be refactored via the writer, but an awful lot of */
+/* hoops to jump through for 2 lines of code! */
+void
+pgp_memory_place_int(pgp_memory_t *mem, unsigned offset, unsigned n,
+ size_t length)
+{
+ if (mem->allocated < offset + length) {
+ (void) fprintf(stderr,
+ "pgp_memory_place_int: bad alloc\n");
+ } else {
+ while (length-- > 0) {
+ mem->buf[offset++] = n >> (length * 8);
+ }
+ }
+}
+
+/**
+ * \ingroup HighLevel_Memory
+ * \brief Retains allocated memory and set length of stored data to zero.
+ * \param mem Memory to clear
+ * \sa pgp_memory_release()
+ * \sa pgp_memory_free()
+ */
+void
+pgp_memory_clear(pgp_memory_t *mem)
+{
+ mem->length = 0;
+}
+
+/**
+\ingroup HighLevel_Memory
+\brief Free memory and associated data
+\param mem Memory to free
+\note This does not free mem itself
+\sa pgp_memory_clear()
+\sa pgp_memory_free()
+*/
+void
+pgp_memory_release(pgp_memory_t *mem)
+{
+ if (mem->mmapped) {
+ (void) munmap(mem->buf, mem->length);
+ } else {
+ free(mem->buf);
+ }
+ mem->buf = NULL;
+ mem->length = 0;
+}
+
+void
+pgp_memory_make_packet(pgp_memory_t *out, pgp_content_enum tag)
+{
+ size_t extra;
+
+ extra = (out->length < 192) ? 1 : (out->length < 8192 + 192) ? 2 : 5;
+ pgp_memory_pad(out, extra + 1);
+ memmove(out->buf + extra + 1, out->buf, out->length);
+
+ out->buf[0] = PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT | tag;
+
+ if (out->length < 192) {
+ out->buf[1] = (uint8_t)out->length;
+ } else if (out->length < 8192 + 192) {
+ out->buf[1] = (uint8_t)((out->length - 192) >> 8) + 192;
+ out->buf[2] = (uint8_t)(out->length - 192);
+ } else {
+ out->buf[1] = 0xff;
+ out->buf[2] = (uint8_t)(out->length >> 24);
+ out->buf[3] = (uint8_t)(out->length >> 16);
+ out->buf[4] = (uint8_t)(out->length >> 8);
+ out->buf[5] = (uint8_t)(out->length);
+ }
+
+ out->length += extra + 1;
+}
+
+/**
+ \ingroup HighLevel_Memory
+ \brief Create a new zeroed pgp_memory_t
+ \return Pointer to new pgp_memory_t
+ \note Free using pgp_memory_free() after use.
+ \sa pgp_memory_free()
+*/
+
+pgp_memory_t *
+pgp_memory_new(void)
+{
+ return calloc(1, sizeof(pgp_memory_t));
+}
+
+/**
+ \ingroup HighLevel_Memory
+ \brief Free memory ptr and associated memory
+ \param mem Memory to be freed
+ \sa pgp_memory_release()
+ \sa pgp_memory_clear()
+*/
+
+void
+pgp_memory_free(pgp_memory_t *mem)
+{
+ pgp_memory_release(mem);
+ free(mem);
+}
+
+/**
+ \ingroup HighLevel_Memory
+ \brief Get length of data stored in pgp_memory_t struct
+ \return Number of bytes in data
+*/
+size_t
+pgp_mem_len(const pgp_memory_t *mem)
+{
+ return mem->length;
+}
+
+/**
+ \ingroup HighLevel_Memory
+ \brief Get data stored in pgp_memory_t struct
+ \return Pointer to data
+*/
+void *
+pgp_mem_data(pgp_memory_t *mem)
+{
+ return mem->buf;
+}
+
+/* read a gile into an pgp_memory_t */
+int
+pgp_mem_readfile(pgp_memory_t *mem, const char *f)
+{
+ struct stat st;
+ FILE *fp;
+ int cc;
+
+ if ((fp = fopen(f, "rb")) == NULL) {
+ (void) fprintf(stderr,
+ "pgp_mem_readfile: can't open \"%s\"\n", f);
+ return 0;
+ }
+ (void) fstat(fileno(fp), &st);
+ mem->allocated = (size_t)st.st_size;
+ mem->buf = mmap(NULL, mem->allocated, PROT_READ,
+ MAP_PRIVATE | MAP_FILE, fileno(fp), 0);
+ if (mem->buf == MAP_FAILED) {
+ /* mmap failed for some reason - try to allocate memory */
+ if ((mem->buf = calloc(1, mem->allocated)) == NULL) {
+ (void) fprintf(stderr, "pgp_mem_readfile: calloc\n");
+ (void) fclose(fp);
+ return 0;
+ }
+ /* read into contents of mem */
+ for (mem->length = 0 ;
+ (cc = (int)read(fileno(fp), &mem->buf[mem->length],
+ (size_t)(mem->allocated - mem->length))) > 0 ;
+ mem->length += (size_t)cc) {
+ }
+ } else {
+ mem->length = mem->allocated;
+ mem->mmapped = 1;
+ }
+ (void) fclose(fp);
+ return (mem->allocated == mem->length);
+}
+
+typedef struct {
+ uint16_t sum;
+} sum16_t;
+
+
+/**
+ * Searches the given map for the given type.
+ * Returns a human-readable descriptive string if found,
+ * returns NULL if not found
+ *
+ * It is the responsibility of the calling function to handle the
+ * error case sensibly (i.e. don't just print out the return string.
+ *
+ */
+static const char *
+str_from_map_or_null(int type, pgp_map_t *map)
+{
+ pgp_map_t *row;
+
+ for (row = map; row->string != NULL; row++) {
+ if (row->type == type) {
+ return row->string;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * Searches the given map for the given type.
+ * Returns a readable string if found, "Unknown" if not.
+ */
+
+const char *
+pgp_str_from_map(int type, pgp_map_t *map)
+{
+ const char *str;
+
+ str = str_from_map_or_null(type, map);
+ return (str) ? str : "Unknown";
+}
+
+#define LINELEN 16
+
+/* show hexadecimal/ascii dump */
+void
+hexdump(FILE *fp, const char *header, const uint8_t *src, size_t length)
+{
+ size_t i;
+ char line[LINELEN + 1];
+
+ (void) fprintf(fp, "%s%s", (header) ? header : "", (header) ? "\n" : "");
+ (void) fprintf(fp, "[%" PRIsize "u char%s]\n", length, (length == 1) ? "" : "s");
+ for (i = 0 ; i < length ; i++) {
+ if (i % LINELEN == 0) {
+ (void) fprintf(fp, "%.5" PRIsize "u | ", i);
+ }
+ (void) fprintf(fp, "%.02x ", (uint8_t)src[i]);
+ line[i % LINELEN] = (isprint(src[i])) ? src[i] : '.';
+ if (i % LINELEN == LINELEN - 1) {
+ line[LINELEN] = 0x0;
+ (void) fprintf(fp, " | %s\n", line);
+ }
+ }
+ if (i % LINELEN != 0) {
+ for ( ; i % LINELEN != 0 ; i++) {
+ (void) fprintf(fp, " ");
+ line[i % LINELEN] = ' ';
+ }
+ line[LINELEN] = 0x0;
+ (void) fprintf(fp, " | %s\n", line);
+ }
+}
+
+/**
+ * \ingroup HighLevel_Functions
+ * \brief Closes down OpenPGP::SDK.
+ *
+ * Close down OpenPGP:SDK, release any resources under the control of
+ * the library.
+ */
+
+void
+pgp_finish(void)
+{
+ pgp_crypto_finish();
+}
+
+static int
+sum16_reader(pgp_stream_t *stream, void *dest_, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ const uint8_t *dest = dest_;
+ sum16_t *arg = pgp_reader_get_arg(readinfo);
+ int r;
+ int n;
+
+ r = pgp_stacked_read(stream, dest_, length, errors, readinfo, cbinfo);
+ if (r < 0) {
+ return r;
+ }
+ for (n = 0; n < r; ++n) {
+ arg->sum = (arg->sum + dest[n]) & 0xffff;
+ }
+ return r;
+}
+
+static void
+sum16_destroyer(pgp_reader_t *readinfo)
+{
+ free(pgp_reader_get_arg(readinfo));
+}
+
+/**
+ \ingroup Internal_Readers_Sum16
+ \param stream Parse settings
+*/
+
+void
+pgp_reader_push_sum16(pgp_stream_t *stream)
+{
+ sum16_t *arg;
+
+ if ((arg = calloc(1, sizeof(*arg))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_push_sum16: bad alloc\n");
+ } else {
+ pgp_reader_push(stream, sum16_reader, sum16_destroyer, arg);
+ }
+}
+
+/**
+ \ingroup Internal_Readers_Sum16
+ \param stream Parse settings
+ \return sum
+*/
+uint16_t
+pgp_reader_pop_sum16(pgp_stream_t *stream)
+{
+ uint16_t sum;
+ sum16_t *arg;
+
+ arg = pgp_reader_get_arg(pgp_readinfo(stream));
+ sum = arg->sum;
+ pgp_reader_pop(stream);
+ free(arg);
+ return sum;
+}
+
+/* small useful functions for setting the file-level debugging levels */
+/* if the debugv list contains the filename in question, we're debugging it */
+
+enum {
+ MAX_DEBUG_NAMES = 32
+};
+
+static int debugc;
+static char *debugv[MAX_DEBUG_NAMES];
+
+/* set the debugging level per filename */
+int
+pgp_set_debug_level(const char *f)
+{
+ const char *name;
+ int i;
+
+ if (f == NULL) {
+ f = "all";
+ }
+ if ((name = strrchr(f, '/')) == NULL) {
+ name = f;
+ } else {
+ name += 1;
+ }
+ for (i = 0; i < debugc && i < MAX_DEBUG_NAMES; i++) {
+ if (strcmp(debugv[i], name) == 0) {
+ return 1;
+ }
+ }
+ if (i == MAX_DEBUG_NAMES) {
+ return 0;
+ }
+ debugv[debugc++] = netpgp_strdup(name);
+ return 1;
+}
+
+/* get the debugging level per filename */
+int
+pgp_get_debug_level(const char *f)
+{
+ const char *name;
+ int i;
+
+ if ((name = strrchr(f, '/')) == NULL) {
+ name = f;
+ } else {
+ name += 1;
+ }
+ for (i = 0; i < debugc; i++) {
+ if (strcmp(debugv[i], "all") == 0 ||
+ strcmp(debugv[i], name) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* return the version for the library */
+const char *
+pgp_get_info(const char *type)
+{
+ if (strcmp(type, "version") == 0) {
+ return NETPGP_VERSION_STRING;
+ }
+ if (strcmp(type, "maintainer") == 0) {
+ return NETPGP_MAINTAINER;
+ }
+ return "[unknown]";
+}
+
+/* local version of asprintf so we don't have to play autoconf games */
+int
+pgp_asprintf(char **ret, const char *fmt, ...)
+{
+ va_list args;
+ char buf[120 * 1024]; /* XXX - "huge" buffer on stack */
+ int cc;
+
+ va_start(args, fmt);
+ cc = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ if ((*ret = calloc(1, (size_t)(cc + 1))) == NULL) {
+ *ret = NULL;
+ return -1;
+ }
+ (void) memcpy(*ret, buf, (size_t)cc);
+ (*ret)[cc] = 0x0;
+ return cc;
+}
+
+void
+netpgp_log(const char *fmt, ...)
+{
+ va_list vp;
+ time_t t;
+ char buf[BUFSIZ * 2];
+ int cc;
+
+ (void) time(&t);
+ cc = snprintf(buf, sizeof(buf), "%.24s: netpgp: ", ctime(&t));
+ va_start(vp, fmt);
+ (void) vsnprintf(&buf[cc], sizeof(buf) - (size_t)cc, fmt, vp);
+ va_end(vp);
+ /* do something with message */
+ /* put into log buffer? */
+}
+
+/* portable replacement for strdup(3) */
+char *
+netpgp_strdup(const char *s)
+{
+ size_t len;
+ char *cp;
+
+ len = strlen(s);
+ if ((cp = calloc(1, len + 1)) != NULL) {
+ (void) memcpy(cp, s, len);
+ cp[len] = 0x0;
+ }
+ return cp;
+}
+
+/* portable replacement for strcasecmp(3) */
+int
+netpgp_strcasecmp(const char *s1, const char *s2)
+{
+ int n;
+
+ for (n = 0 ; *s1 && *s2 && (n = tolower((uint8_t)*s1) - tolower((uint8_t)*s2)) == 0 ; s1++, s2++) {
+ }
+ return n;
+}
diff --git a/libs/netpgp/src/lib/netpgp.c b/libs/netpgp/src/lib/netpgp.c
new file mode 100644
index 00000000..fa4915fb
--- /dev/null
+++ b/libs/netpgp/src/lib/netpgp.c
@@ -0,0 +1,1955 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: netpgp.c,v 1.96 2012/02/22 06:58:54 agc Exp $");
+#endif
+
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#include
+
+#ifdef HAVE_LIMITS_H
+#include
+#endif
+
+#include
+
+#include "packet.h"
+#include "packet-parse.h"
+#include "keyring.h"
+#include "errors.h"
+#include "packet-show.h"
+#include "create.h"
+#include "netpgpsdk.h"
+#include "memory.h"
+#include "validate.h"
+#include "readerwriter.h"
+#include "netpgpdefs.h"
+#include "crypto.h"
+#include "ssh2pgp.h"
+#include "defs.h"
+
+/* read any gpg config file */
+static int
+conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length)
+{
+ regmatch_t matchv[10];
+ regex_t keyre;
+ char buf[BUFSIZ];
+ FILE *fp;
+
+ __PGP_USED(netpgp);
+ (void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir);
+ if ((fp = fopen(buf, "r")) == NULL) {
+ return 0;
+ }
+ (void) memset(&keyre, 0x0, sizeof(keyre));
+ (void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
+ REG_EXTENDED);
+ while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
+ if (regexec(&keyre, buf, 10, matchv, 0) == 0) {
+ (void) memcpy(userid, &buf[(int)matchv[1].rm_so],
+ MIN((unsigned)(matchv[1].rm_eo -
+ matchv[1].rm_so), length));
+ if (netpgp->passfp == NULL) {
+ (void) fprintf(stderr,
+ "netpgp: default key set to \"%.*s\"\n",
+ (int)(matchv[1].rm_eo - matchv[1].rm_so),
+ &buf[(int)matchv[1].rm_so]);
+ }
+ }
+ }
+ (void) fclose(fp);
+ regfree(&keyre);
+ return 1;
+}
+
+/* small function to pretty print an 8-character raw userid */
+static char *
+userid_to_id(const uint8_t *userid, char *id)
+{
+ static const char *hexes = "0123456789abcdef";
+ int i;
+
+ for (i = 0; i < 8 ; i++) {
+ id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
+ id[(i * 2) + 1] = hexes[userid[i] & 0xf];
+ }
+ id[8 * 2] = 0x0;
+ return id;
+}
+
+/* print out the successful signature information */
+static void
+resultp(pgp_io_t *io,
+ const char *f,
+ pgp_validation_t *res,
+ pgp_keyring_t *ring)
+{
+ const pgp_key_t *key;
+ pgp_pubkey_t *sigkey;
+ unsigned from;
+ unsigned i;
+ time_t t;
+ char id[MAX_ID_LENGTH + 1];
+
+ for (i = 0; i < res->validc; i++) {
+ (void) fprintf(io->res,
+ "Good signature for %s made %s",
+ (f) ? f : "",
+ ctime(&res->valid_sigs[i].birthtime));
+ if (res->duration > 0) {
+ t = res->birthtime + res->duration;
+ (void) fprintf(io->res, "Valid until %s", ctime(&t));
+ }
+ (void) fprintf(io->res,
+ "using %s key %s\n",
+ pgp_show_pka(res->valid_sigs[i].key_alg),
+ userid_to_id(res->valid_sigs[i].signer_id, id));
+ from = 0;
+ key = pgp_getkeybyid(io, ring,
+ (const uint8_t *) res->valid_sigs[i].signer_id,
+ &from, &sigkey);
+ if (sigkey == &key->enckey) {
+ (void) fprintf(io->res,
+ "WARNING: signature for %s made with encryption key\n",
+ (f) ? f : "");
+ }
+ pgp_print_keydata(io, ring, key, "signature ", &key->key.pubkey, 0);
+ }
+}
+
+/* check there's enough space in the arrays */
+static int
+size_arrays(netpgp_t *netpgp, unsigned needed)
+{
+ char **temp;
+
+ if (netpgp->size == 0) {
+ /* only get here first time around */
+ netpgp->size = needed;
+ if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
+ (void) fprintf(stderr, "size_arrays: bad alloc\n");
+ return 0;
+ }
+ if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
+ free(netpgp->name);
+ (void) fprintf(stderr, "size_arrays: bad alloc\n");
+ return 0;
+ }
+ } else if (netpgp->c == netpgp->size) {
+ /* only uses 'needed' when filled array */
+ netpgp->size += needed;
+ temp = realloc(netpgp->name, sizeof(char *) * needed);
+ if (temp == NULL) {
+ (void) fprintf(stderr, "size_arrays: bad alloc\n");
+ return 0;
+ }
+ netpgp->name = temp;
+ temp = realloc(netpgp->value, sizeof(char *) * needed);
+ if (temp == NULL) {
+ (void) fprintf(stderr, "size_arrays: bad alloc\n");
+ return 0;
+ }
+ netpgp->value = temp;
+ }
+ return 1;
+}
+
+/* find the name in the array */
+static int
+findvar(netpgp_t *netpgp, const char *name)
+{
+ unsigned i;
+
+ for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
+ }
+ return (i == netpgp->c) ? -1 : (int)i;
+}
+
+/* read a keyring and return it */
+static void *
+readkeyring(netpgp_t *netpgp, const char *name)
+{
+ pgp_keyring_t *keyring;
+ const unsigned noarmor = 0;
+ char f[MAXPATHLEN];
+ char *filename;
+ char *homedir;
+
+ homedir = netpgp_getvar(netpgp, "homedir");
+ if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
+ (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
+ filename = f;
+ }
+ if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
+ (void) fprintf(stderr, "readkeyring: bad alloc\n");
+ return NULL;
+ }
+ if (!pgp_keyring_fileread(keyring, noarmor, filename)) {
+ free(keyring);
+ (void) fprintf(stderr, "Can't read %s %s\n", name, filename);
+ return NULL;
+ }
+ netpgp_setvar(netpgp, name, filename);
+ return keyring;
+}
+
+/* read keys from ssh key files */
+static int
+readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey)
+{
+ pgp_keyring_t *pubring;
+ pgp_keyring_t *secring;
+ struct stat st;
+ unsigned hashtype;
+ char *hash;
+ char f[MAXPATHLEN];
+ char *filename;
+
+ if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
+ /* set reasonable default for RSA key */
+ (void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir);
+ filename = f;
+ } else if (strcmp(&filename[strlen(filename) - 4], ".pub") != 0) {
+ /* got ssh keys, check for pub file name */
+ (void) snprintf(f, sizeof(f), "%s.pub", filename);
+ filename = f;
+ }
+ /* check the pub file exists */
+ if (stat(filename, &st) != 0) {
+ (void) fprintf(stderr, "readsshkeys: bad pubkey filename '%s'\n", filename);
+ return 0;
+ }
+ if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
+ (void) fprintf(stderr, "readsshkeys: bad alloc\n");
+ return 0;
+ }
+ /* openssh2 keys use md5 by default */
+ hashtype = PGP_HASH_MD5;
+ if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) {
+ /* openssh 2 hasn't really caught up to anything else yet */
+ if (netpgp_strcasecmp(hash, "md5") == 0) {
+ hashtype = PGP_HASH_MD5;
+ } else if (netpgp_strcasecmp(hash, "sha1") == 0) {
+ hashtype = PGP_HASH_SHA1;
+ } else if (netpgp_strcasecmp(hash, "sha256") == 0) {
+ hashtype = PGP_HASH_SHA256;
+ }
+ }
+ if (!pgp_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) {
+ free(pubring);
+ (void) fprintf(stderr, "readsshkeys: can't read %s\n",
+ filename);
+ return 0;
+ }
+ if (netpgp->pubring == NULL) {
+ netpgp->pubring = pubring;
+ } else {
+ pgp_append_keyring(netpgp->pubring, pubring);
+ }
+ if (needseckey) {
+ netpgp_setvar(netpgp, "sshpubfile", filename);
+ /* try to take the ".pub" off the end */
+ if (filename == f) {
+ f[strlen(f) - 4] = 0x0;
+ } else {
+ (void) snprintf(f, sizeof(f), "%.*s",
+ (int)strlen(filename) - 4, filename);
+ filename = f;
+ }
+ if ((secring = calloc(1, sizeof(*secring))) == NULL) {
+ free(pubring);
+ (void) fprintf(stderr, "readsshkeys: bad alloc\n");
+ return 0;
+ }
+ if (!pgp_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) {
+ free(pubring);
+ free(secring);
+ (void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename);
+ return 0;
+ }
+ netpgp->secring = secring;
+ netpgp_setvar(netpgp, "sshsecfile", filename);
+ }
+ return 1;
+}
+
+/* get the uid of the first key in the keyring */
+static int
+get_first_ring(pgp_keyring_t *ring, char *id, size_t len, int last)
+{
+ uint8_t *src;
+ int i;
+ int n;
+
+ if (ring == NULL) {
+ return 0;
+ }
+ (void) memset(id, 0x0, len);
+ src = ring->keys[(last) ? ring->keyc - 1 : 0].sigid;
+ for (i = 0, n = 0 ; i < PGP_KEY_ID_SIZE ; i += 2) {
+ n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
+ }
+ id[n] = 0x0;
+ return 1;
+}
+
+/* find the time - in a specific %Y-%m-%d format - using a regexp */
+static int
+grabdate(char *s, int64_t *t)
+{
+ static regex_t r;
+ static int compiled;
+ regmatch_t matches[10];
+ struct tm tm;
+
+ if (!compiled) {
+ compiled = 1;
+ (void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
+ }
+ if (regexec(&r, s, 10, matches, 0) == 0) {
+ (void) memset(&tm, 0x0, sizeof(tm));
+ tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
+ tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
+ tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
+ *t = mktime(&tm);
+ return 1;
+ }
+ return 0;
+}
+
+/* get expiration in seconds */
+static uint64_t
+get_duration(char *s)
+{
+ uint64_t now;
+ int64_t t;
+ char *mult;
+
+ if (s == NULL) {
+ return 0;
+ }
+ now = (uint64_t)strtoull(s, NULL, 10);
+ if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
+ switch(*mult) {
+ case 'h':
+ return now * 60 * 60;
+ case 'd':
+ return now * 60 * 60 * 24;
+ case 'w':
+ return now * 60 * 60 * 24 * 7;
+ case 'm':
+ return now * 60 * 60 * 24 * 31;
+ case 'y':
+ return now * 60 * 60 * 24 * 365;
+ }
+ }
+ if (grabdate(s, &t)) {
+ return t;
+ }
+ return (uint64_t)strtoll(s, NULL, 10);
+}
+
+/* get birthtime in seconds */
+static int64_t
+get_birthtime(char *s)
+{
+ int64_t t;
+
+ if (s == NULL) {
+ return time(NULL);
+ }
+ if (grabdate(s, &t)) {
+ return t;
+ }
+ return (uint64_t)strtoll(s, NULL, 10);
+}
+
+/* resolve the userid */
+static const pgp_key_t *
+resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *userid)
+{
+ const pgp_key_t *key;
+ pgp_io_t *io;
+
+ if (userid == NULL) {
+ userid = netpgp_getvar(netpgp, "userid");
+ if (userid == NULL)
+ return NULL;
+ } else if (userid[0] == '0' && userid[1] == 'x') {
+ userid += 2;
+ }
+ io = netpgp->io;
+ if ((key = pgp_getkeybyname(io, keyring, userid)) == NULL) {
+ (void) fprintf(io->errs, "Can't find key '%s'\n", userid);
+ }
+ return key;
+}
+
+/* append a key to a keyring */
+static int
+appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
+{
+ pgp_output_t *create;
+ const unsigned noarmor = 0;
+ int fd;
+
+ if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
+ fd = pgp_setup_file_write(&create, ringfile, 0);
+ }
+ if (fd < 0) {
+ (void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
+ return 0;
+ }
+ if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
+ (void) fprintf(io->errs, "Cannot write pubkey\n");
+ return 0;
+ }
+ pgp_teardown_file_write(create, fd);
+ return 1;
+}
+
+/* return 1 if the file contains ascii-armoured text */
+static unsigned
+isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
+{
+ regmatch_t matches[10];
+ unsigned armoured;
+ regex_t r;
+ FILE *fp;
+ char buf[BUFSIZ];
+
+ armoured = 0;
+ (void) regcomp(&r, text, REG_EXTENDED);
+ if (f) {
+ if ((fp = fopen(f, "r")) == NULL) {
+ (void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f);
+ regfree(&r);
+ return 0;
+ }
+ if (fgets(buf, (int)sizeof(buf), fp) != NULL) {
+ if (regexec(&r, buf, 10, matches, 0) == 0) {
+ armoured = 1;
+ }
+ }
+ (void) fclose(fp);
+ } else {
+ if (regexec(&r, memory, 10, matches, 0) == 0) {
+ armoured = 1;
+ }
+ }
+ regfree(&r);
+ return armoured;
+}
+
+/* vararg print function */
+static void
+p(FILE *fp, const char *s, ...)
+{
+ va_list args;
+
+ va_start(args, s);
+ while (s != NULL) {
+ (void) fprintf(fp, "%s", s);
+ s = va_arg(args, char *);
+ }
+ va_end(args);
+}
+
+/* print a JSON object to the FILE stream */
+static void
+pobj(FILE *fp, mj_t *obj, int depth)
+{
+ unsigned i;
+ char *s;
+
+ if (obj == NULL) {
+ (void) fprintf(stderr, "No object found\n");
+ return;
+ }
+ for (i = 0 ; i < (unsigned)depth ; i++) {
+ p(fp, " ", NULL);
+ }
+ switch(obj->type) {
+ case MJ_NULL:
+ case MJ_FALSE:
+ case MJ_TRUE:
+ p(fp, (obj->type == MJ_NULL) ? "null" : (obj->type == MJ_FALSE) ? "false" : "true", NULL);
+ break;
+ case MJ_NUMBER:
+ p(fp, obj->value.s, NULL);
+ break;
+ case MJ_STRING:
+ if ((i = mj_asprint(&s, obj, MJ_HUMAN)) > 2) {
+ (void) fprintf(fp, "%.*s", (int)i - 2, &s[1]);
+ free(s);
+ }
+ break;
+ case MJ_ARRAY:
+ for (i = 0 ; i < obj->c ; i++) {
+ pobj(fp, &obj->value.v[i], depth + 1);
+ if (i < obj->c - 1) {
+ (void) fprintf(fp, ", ");
+ }
+ }
+ (void) fprintf(fp, "\n");
+ break;
+ case MJ_OBJECT:
+ for (i = 0 ; i < obj->c ; i += 2) {
+ pobj(fp, &obj->value.v[i], depth + 1);
+ p(fp, ": ", NULL);
+ pobj(fp, &obj->value.v[i + 1], 0);
+ if (i < obj->c - 1) {
+ p(fp, ", ", NULL);
+ }
+ }
+ p(fp, "\n", NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+/* return the time as a string */
+static char *
+ptimestr(char *dest, size_t size, time_t t)
+{
+ struct tm *tm;
+
+ tm = gmtime(&t);
+ (void) snprintf(dest, size, "%04d-%02d-%02d",
+ tm->tm_year + 1900,
+ tm->tm_mon + 1,
+ tm->tm_mday);
+ return dest;
+}
+
+/* format a JSON object */
+static void
+format_json_key(FILE *fp, mj_t *obj, const int psigs)
+{
+ int64_t birthtime;
+ int64_t duration;
+ time_t now;
+ char tbuf[32];
+ char *s;
+ mj_t *sub;
+ int i;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ mj_asprint(&s, obj, MJ_HUMAN);
+ (void) fprintf(stderr, "formatobj: json is '%s'\n", s);
+ free(s);
+ }
+ if (obj->c == 2 && obj->value.v[1].type == MJ_STRING &&
+ strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) {
+ /* whole key has been rovoked - just return */
+ return;
+ }
+ pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0);
+ p(fp, " ", NULL);
+ pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0);
+ p(fp, "/", NULL);
+ pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0);
+ p(fp, " ", NULL);
+ pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0);
+ birthtime = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10);
+ p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL);
+ duration = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10);
+ if (duration > 0) {
+ now = time(NULL);
+ p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ",
+ ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL);
+ }
+ p(fp, "\n", "Key fingerprint: ", NULL);
+ pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0);
+ p(fp, "\n", NULL);
+ /* go to field after \"duration\" */
+ for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) {
+ if (strcmp(obj->value.v[i].value.s, "uid") == 0) {
+ sub = &obj->value.v[i + 1];
+ p(fp, "uid", NULL);
+ pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */
+ pobj(fp, &sub->value.v[1], 1); /* any revocation */
+ p(fp, "\n", NULL);
+ } else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) {
+ sub = &obj->value.v[i + 1];
+ p(fp, "encryption", NULL);
+ pobj(fp, &sub->value.v[0], 1); /* size */
+ p(fp, "/", NULL);
+ pobj(fp, &sub->value.v[1], 0); /* alg */
+ p(fp, " ", NULL);
+ pobj(fp, &sub->value.v[2], 0); /* id */
+ p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
+ (time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
+ "\n", NULL);
+ } else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
+ sub = &obj->value.v[i + 1];
+ p(fp, "sig", NULL);
+ pobj(fp, &sub->value.v[0], 8); /* size */
+ p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
+ (time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
+ " ", NULL); /* time */
+ pobj(fp, &sub->value.v[2], 0); /* human name */
+ p(fp, "\n", NULL);
+ } else {
+ fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
+ pobj(fp, &obj->value.v[i], 0); /* human name */
+ }
+ }
+ p(fp, "\n", NULL);
+}
+
+/* save a pgp pubkey to a temp file */
+static int
+savepubkey(char *res, char *f, size_t size)
+{
+ size_t len;
+ int cc;
+ int wc;
+ int fd;
+
+ (void) snprintf(f, size, "/tmp/pgp2ssh.XXXXXXX");
+ if ((fd = mkstemp(f)) < 0) {
+ (void) fprintf(stderr, "can't create temp file '%s'\n", f);
+ return 0;
+ }
+ len = strlen(res);
+ for (cc = 0 ; (wc = (int)write(fd, &res[cc], len - (size_t)cc)) > 0 ; cc += wc) {
+ }
+ (void) close(fd);
+ return 1;
+}
+
+/* format a uint32_t */
+static int
+formatu32(uint8_t *buffer, uint32_t value)
+{
+ buffer[0] = (uint8_t)(value >> 24) & 0xff;
+ buffer[1] = (uint8_t)(value >> 16) & 0xff;
+ buffer[2] = (uint8_t)(value >> 8) & 0xff;
+ buffer[3] = (uint8_t)value & 0xff;
+ return sizeof(uint32_t);
+}
+
+/* format a string as (len, string) */
+static int
+formatstring(char *buffer, const uint8_t *s, size_t len)
+{
+ int cc;
+
+ cc = formatu32((uint8_t *)buffer, (uint32_t)len);
+ (void) memcpy(&buffer[cc], s, len);
+ return cc + (int)len;
+}
+
+/* format a bignum, checking for "interesting" high bit values */
+static int
+formatbignum(char *buffer, BIGNUM *bn)
+{
+ size_t len;
+ uint8_t *cp;
+ int cc;
+
+ len = (size_t) BN_num_bytes(bn);
+ if ((cp = calloc(1, len + 1)) == NULL) {
+ (void) fprintf(stderr, "calloc failure in formatbignum\n");
+ return 0;
+ }
+ (void) BN_bn2bin(bn, cp + 1);
+ cp[0] = 0x0;
+ cc = (cp[1] & 0x80) ? formatstring(buffer, cp, len + 1) : formatstring(buffer, &cp[1], len);
+ free(cp);
+ return cc;
+}
+
+#define MAX_PASSPHRASE_ATTEMPTS 3
+#define INFINITE_ATTEMPTS -1
+
+/* get the passphrase from the user */
+static int
+find_passphrase(FILE *passfp, const char *id, char *passphrase, size_t size, int attempts)
+{
+ char prompt[BUFSIZ];
+ char buf[128];
+ char *cp;
+ int cc;
+ int i;
+
+ if (passfp) {
+ if (fgets(passphrase, (int)size, passfp) == NULL) {
+ return 0;
+ }
+ return (int)strlen(passphrase);
+ }
+ for (i = 0 ; i < attempts ; i++) {
+ (void) snprintf(prompt, sizeof(prompt), "Enter passphrase for %.16s: ", id);
+ if ((cp = getpass(prompt)) == NULL) {
+ break;
+ }
+ cc = snprintf(buf, sizeof(buf), "%s", cp);
+ (void) snprintf(prompt, sizeof(prompt), "Repeat passphrase for %.16s: ", id);
+ if ((cp = getpass(prompt)) == NULL) {
+ break;
+ }
+ cc = snprintf(passphrase, size, "%s", cp);
+ if (strcmp(buf, passphrase) == 0) {
+ (void) memset(buf, 0x0, sizeof(buf));
+ return cc;
+ }
+ }
+ (void) memset(buf, 0x0, sizeof(buf));
+ (void) memset(passphrase, 0x0, size);
+ return 0;
+}
+
+/***************************************************************************/
+/* exported functions start here */
+/***************************************************************************/
+
+/* initialise a netpgp_t structure */
+int
+netpgp_init(netpgp_t *netpgp)
+{
+ pgp_io_t *io;
+ time_t t;
+ char id[MAX_ID_LENGTH];
+ char *homedir;
+ char *userid;
+ char *stream;
+ char *passfd;
+ char *results;
+ int coredumps;
+ int last;
+
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit limit;
+
+ coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
+ if (!coredumps) {
+ (void) memset(&limit, 0x0, sizeof(limit));
+ if (setrlimit(RLIMIT_CORE, &limit) != 0) {
+ (void) fprintf(stderr,
+ "netpgp: warning - can't turn off core dumps\n");
+ coredumps = 1;
+ }
+ }
+#else
+ coredumps = 1;
+#endif
+ if ((io = calloc(1, sizeof(*io))) == NULL) {
+ (void) fprintf(stderr, "netpgp_init: bad alloc\n");
+ return 0;
+ }
+ io->outs = stdout;
+ if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
+ strcmp(stream, "") == 0) {
+ io->outs = stderr;
+ }
+ io->errs = stderr;
+ if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
+ strcmp(stream, "") == 0) {
+ io->errs = stdout;
+ }
+ if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
+ io->res = io->errs;
+ } else if (strcmp(results, "") == 0) {
+ io->res = stdout;
+ } else if (strcmp(results, "") == 0) {
+ io->res = stderr;
+ } else {
+ if ((io->res = fopen(results, "w")) == NULL) {
+ (void) fprintf(io->errs, "Can't open results %s for writing\n",
+ results);
+ free(io);
+ return 0;
+ }
+ }
+ netpgp->io = io;
+ /* get passphrase from an fd */
+ if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
+ (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
+ (void) fprintf(io->errs, "Can't open fd %s for reading\n",
+ passfd);
+ return 0;
+ }
+ /* warn if core dumps are enabled */
+ if (coredumps) {
+ (void) fprintf(io->errs,
+ "netpgp: warning: core dumps enabled\n");
+ }
+ /* get home directory - where keyrings are in a subdir */
+ if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
+ (void) fprintf(io->errs, "netpgp: bad homedir\n");
+ return 0;
+ }
+ if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
+ /* read from ordinary pgp keyrings */
+ netpgp->pubring = readkeyring(netpgp, "pubring");
+ if (netpgp->pubring == NULL) {
+ (void) fprintf(io->errs, "Can't read pub keyring\n");
+ return 0;
+ }
+ /* if a userid has been given, we'll use it */
+ if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
+ /* also search in config file for default id */
+ (void) memset(id, 0x0, sizeof(id));
+ (void) conffile(netpgp, homedir, id, sizeof(id));
+ if (id[0] != 0x0) {
+ netpgp_setvar(netpgp, "userid", userid = id);
+ }
+ }
+ /* only read secret keys if we need to */
+ if (netpgp_getvar(netpgp, "need seckey")) {
+ /* read the secret ring */
+ netpgp->secring = readkeyring(netpgp, "secring");
+ if (netpgp->secring == NULL) {
+ (void) fprintf(io->errs, "Can't read sec keyring\n");
+ return 0;
+ }
+ /* now, if we don't have a valid user, use the first in secring */
+ if (!userid && netpgp_getvar(netpgp, "need userid") != NULL) {
+ /* signing - need userid and sec key */
+ (void) memset(id, 0x0, sizeof(id));
+ if (get_first_ring(netpgp->secring, id, sizeof(id), 0)) {
+ netpgp_setvar(netpgp, "userid", userid = id);
+ }
+ }
+ } else if (netpgp_getvar(netpgp, "need userid") != NULL) {
+ /* encrypting - get first in pubring */
+ if (!userid && get_first_ring(netpgp->pubring, id, sizeof(id), 0)) {
+ (void) netpgp_setvar(netpgp, "userid", userid = id);
+ }
+ }
+ if (!userid && netpgp_getvar(netpgp, "need userid")) {
+ /* if we don't have a user id, and we need one, fail */
+ (void) fprintf(io->errs, "Cannot find user id\n");
+ return 0;
+ }
+ } else {
+ /* read from ssh keys */
+ last = (netpgp->pubring != NULL);
+ if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
+ (void) fprintf(io->errs, "Can't read ssh keys\n");
+ return 0;
+ }
+ if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
+ get_first_ring(netpgp->pubring, id, sizeof(id), last);
+ netpgp_setvar(netpgp, "userid", userid = id);
+ }
+ if (userid == NULL) {
+ if (netpgp_getvar(netpgp, "need userid") != NULL) {
+ (void) fprintf(io->errs,
+ "Cannot find user id\n");
+ return 0;
+ }
+ } else {
+ (void) netpgp_setvar(netpgp, "userid", userid);
+ }
+ }
+ t = time(NULL);
+ netpgp_setvar(netpgp, "initialised", ctime(&t));
+ return 1;
+}
+
+/* finish off with the netpgp_t struct */
+int
+netpgp_end(netpgp_t *netpgp)
+{
+ unsigned i;
+
+ for (i = 0 ; i < netpgp->c ; i++) {
+ if (netpgp->name[i] != NULL) {
+ free(netpgp->name[i]);
+ }
+ if (netpgp->value[i] != NULL) {
+ free(netpgp->value[i]);
+ }
+ }
+ if (netpgp->name != NULL) {
+ free(netpgp->name);
+ }
+ if (netpgp->value != NULL) {
+ free(netpgp->value);
+ }
+ if (netpgp->pubring != NULL) {
+ pgp_keyring_free(netpgp->pubring);
+ }
+ if (netpgp->secring != NULL) {
+ pgp_keyring_free(netpgp->secring);
+ }
+ free(netpgp->io);
+ return 1;
+}
+
+/* list the keys in a keyring */
+int
+netpgp_list_keys(netpgp_t *netpgp, const int psigs)
+{
+ if (netpgp->pubring == NULL) {
+ (void) fprintf(stderr, "No keyring\n");
+ return 0;
+ }
+ return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
+}
+
+/* list the keys in a keyring, returning a JSON encoded string */
+int
+netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
+{
+ mj_t obj;
+ int ret;
+
+ if (netpgp->pubring == NULL) {
+ (void) fprintf(stderr, "No keyring\n");
+ return 0;
+ }
+ (void) memset(&obj, 0x0, sizeof(obj));
+ if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
+ (void) fprintf(stderr, "No keys in keyring\n");
+ return 0;
+ }
+ ret = mj_asprint(json, &obj, MJ_JSON_ENCODE);
+ mj_delete(&obj);
+ return ret;
+}
+
+DEFINE_ARRAY(strings_t, char *);
+
+#ifndef HKP_VERSION
+#define HKP_VERSION 1
+#endif
+
+/* find and list some keys in a keyring */
+int
+netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
+{
+ const pgp_key_t *key;
+ unsigned k;
+ strings_t pubs;
+ FILE *fp = (FILE *)vp;
+
+ if (name[0] == '0' && name[1] == 'x') {
+ name += 2;
+ }
+ (void) memset(&pubs, 0x0, sizeof(pubs));
+ k = 0;
+ do {
+ key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
+ name, &k);
+ if (key != NULL) {
+ ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
+ "netpgp_match_keys", return 0);
+ if (strcmp(fmt, "mr") == 0) {
+ pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
+ key, &pubs.v[pubs.c],
+ &key->key.pubkey, psigs);
+ } else {
+ pgp_sprint_keydata(netpgp->io, netpgp->pubring,
+ key, &pubs.v[pubs.c],
+ "signature ",
+ &key->key.pubkey, psigs);
+ }
+ if (pubs.v[pubs.c] != NULL) {
+ pubs.c += 1;
+ }
+ k += 1;
+ }
+ } while (key != NULL);
+ if (strcmp(fmt, "mr") == 0) {
+ (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
+ } else {
+ (void) fprintf(fp, "%d key%s found\n", pubs.c,
+ (pubs.c == 1) ? "" : "s");
+ }
+ for (k = 0 ; k < pubs.c ; k++) {
+ (void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
+ free(pubs.v[k]);
+ }
+ free(pubs.v);
+ return pubs.c;
+}
+
+/* find and list some keys in a keyring - return JSON string */
+int
+netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
+{
+ const pgp_key_t *key;
+ unsigned k;
+ mj_t id_array;
+ char *newkey;
+ int ret;
+
+ if (name[0] == '0' && name[1] == 'x') {
+ name += 2;
+ }
+ (void) memset(&id_array, 0x0, sizeof(id_array));
+ k = 0;
+ *json = NULL;
+ mj_create(&id_array, "array");
+ do {
+ key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
+ name, &k);
+ if (key != NULL) {
+ if (strcmp(fmt, "mr") == 0) {
+ pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
+ key, &newkey,
+ &key->key.pubkey, 0);
+ if (newkey) {
+ printf("%s\n", newkey);
+ free(newkey);
+ }
+ } else {
+ ALLOC(mj_t, id_array.value.v, id_array.size,
+ id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
+ pgp_sprint_mj(netpgp->io, netpgp->pubring,
+ key, &id_array.value.v[id_array.c++],
+ "signature ",
+ &key->key.pubkey, psigs);
+ }
+ k += 1;
+ }
+ } while (key != NULL);
+ ret = mj_asprint(json, &id_array, MJ_JSON_ENCODE);
+ mj_delete(&id_array);
+ return ret;
+}
+
+/* find and list some public keys in a keyring */
+int
+netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
+{
+ const pgp_key_t *key;
+ unsigned k;
+ ssize_t cc;
+ char out[1024 * 64];
+ FILE *fp = (FILE *)vp;
+
+ k = 0;
+ do {
+ key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
+ name, &k);
+ if (key != NULL) {
+ cc = pgp_sprint_pubkey(key, out, sizeof(out));
+ (void) fprintf(fp, "%.*s", (int)cc, out);
+ k += 1;
+ }
+ } while (key != NULL);
+ return k;
+}
+
+/* find a key in a keyring */
+int
+netpgp_find_key(netpgp_t *netpgp, char *id)
+{
+ pgp_io_t *io;
+
+ io = netpgp->io;
+ if (id == NULL) {
+ (void) fprintf(io->errs, "NULL id to search for\n");
+ return 0;
+ }
+ return pgp_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
+}
+
+/* get a key in a keyring */
+char *
+netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
+{
+ const pgp_key_t *key;
+ char *newkey;
+
+ if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
+ return NULL;
+ }
+ if (strcmp(fmt, "mr") == 0) {
+ return (pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
+ key, &newkey,
+ &key->key.pubkey,
+ netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
+ }
+ return (pgp_sprint_keydata(netpgp->io, netpgp->pubring,
+ key, &newkey, "signature",
+ &key->key.pubkey,
+ netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
+}
+
+/* export a given key */
+char *
+netpgp_export_key(netpgp_t *netpgp, char *name)
+{
+ const pgp_key_t *key;
+ pgp_io_t *io;
+
+ io = netpgp->io;
+ if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
+ return NULL;
+ }
+ return pgp_export_key(io, key, NULL);
+}
+
+#define IMPORT_ARMOR_HEAD "-----BEGIN PGP PUBLIC KEY BLOCK-----"
+
+/* import a key into our keyring */
+int
+netpgp_import_key(netpgp_t *netpgp, char *f)
+{
+ pgp_io_t *io;
+ unsigned realarmor;
+ int done;
+
+ io = netpgp->io;
+ realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
+ done = pgp_keyring_fileread(netpgp->pubring, realarmor, f);
+ if (!done) {
+ (void) fprintf(io->errs, "Cannot import key from file %s\n", f);
+ return 0;
+ }
+ return pgp_keyring_list(io, netpgp->pubring, 0);
+}
+
+#define ID_OFFSET 38
+
+/* generate a new key */
+int
+netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
+{
+ pgp_output_t *create;
+ const unsigned noarmor = 0;
+ pgp_key_t *key;
+ pgp_io_t *io;
+ uint8_t *uid;
+ char passphrase[128];
+ char newid[1024];
+ char filename[MAXPATHLEN];
+ char dir[MAXPATHLEN];
+ char *cp;
+ char *ringfile;
+ char *numtries;
+ int attempts;
+ int passc;
+ int fd;
+ int cc;
+
+ uid = NULL;
+ io = netpgp->io;
+ /* generate a new key */
+ if (id) {
+ (void) snprintf(newid, sizeof(newid), "%s", id);
+ } else {
+ (void) snprintf(newid, sizeof(newid),
+ "RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
+ }
+ uid = (uint8_t *)newid;
+ key = pgp_rsa_new_selfsign_key(numbits, 65537UL, uid,
+ netpgp_getvar(netpgp, "hash"),
+ netpgp_getvar(netpgp, "cipher"));
+ if (key == NULL) {
+ (void) fprintf(io->errs, "Cannot generate key\n");
+ return 0;
+ }
+ cp = NULL;
+ pgp_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0);
+ (void) fprintf(stdout, "%s", cp);
+ /* write public key */
+ cc = snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[ID_OFFSET]);
+ netpgp_setvar(netpgp, "generated userid", &dir[cc - 16]);
+ if (mkdir(dir, 0700) < 0) {
+ (void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
+ return 0;
+ }
+ (void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
+ (void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
+ if (!appendkey(io, key, ringfile)) {
+ (void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
+ return 0;
+ }
+ if (netpgp->pubring != NULL) {
+ pgp_keyring_free(netpgp->pubring);
+ }
+ /* write secret key */
+ (void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
+ if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
+ fd = pgp_setup_file_write(&create, ringfile, 0);
+ }
+ if (fd < 0) {
+ (void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
+ return 0;
+ }
+ /* get the passphrase */
+ if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
+ (attempts = atoi(numtries)) <= 0) {
+ attempts = MAX_PASSPHRASE_ATTEMPTS;
+ } else if (strcmp(numtries, "unlimited") == 0) {
+ attempts = INFINITE_ATTEMPTS;
+ }
+ passc = find_passphrase(netpgp->passfp, &cp[ID_OFFSET], passphrase, sizeof(passphrase), attempts);
+ if (!pgp_write_xfer_seckey(create, key, (uint8_t *)passphrase, (const unsigned)passc, noarmor)) {
+ (void) fprintf(io->errs, "Cannot write seckey\n");
+ return 0;
+ }
+ pgp_teardown_file_write(create, fd);
+ if (netpgp->secring != NULL) {
+ pgp_keyring_free(netpgp->secring);
+ }
+ pgp_keydata_free(key);
+ free(cp);
+ return 1;
+}
+
+/* encrypt a file */
+int
+netpgp_encrypt_file(netpgp_t *netpgp,
+ const char *userid,
+ const char *f,
+ char *out,
+ int armored)
+{
+ const pgp_key_t *key;
+ const unsigned overwrite = 1;
+ const char *suffix;
+ pgp_io_t *io;
+ char outname[MAXPATHLEN];
+
+ io = netpgp->io;
+ if (f == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_encrypt_file: no filename specified\n");
+ return 0;
+ }
+ suffix = (armored) ? ".asc" : ".gpg";
+ /* get key with which to sign */
+ if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
+ return 0;
+ }
+ if (out == NULL) {
+ (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
+ out = outname;
+ }
+ return (int)pgp_encrypt_file(io, f, out, key, (unsigned)armored,
+ overwrite, netpgp_getvar(netpgp, "cipher"));
+}
+
+#define ARMOR_HEAD "-----BEGIN PGP MESSAGE-----"
+
+/* decrypt a file */
+int
+netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
+{
+ const unsigned overwrite = 1;
+ pgp_io_t *io;
+ unsigned realarmor;
+ unsigned sshkeys;
+ char *numtries;
+ int attempts;
+
+ __PGP_USED(armored);
+ io = netpgp->io;
+ if (f == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_decrypt_file: no filename specified\n");
+ return 0;
+ }
+ realarmor = isarmoured(io, f, NULL, ARMOR_HEAD);
+ sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
+ if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
+ (attempts = atoi(numtries)) <= 0) {
+ attempts = MAX_PASSPHRASE_ATTEMPTS;
+ } else if (strcmp(numtries, "unlimited") == 0) {
+ attempts = INFINITE_ATTEMPTS;
+ }
+ return pgp_decrypt_file(netpgp->io, f, out, netpgp->secring,
+ netpgp->pubring,
+ realarmor, overwrite, sshkeys,
+ netpgp->passfp, attempts, get_passphrase_cb);
+}
+
+/* sign a file */
+int
+netpgp_sign_file(netpgp_t *netpgp,
+ const char *userid,
+ const char *f,
+ char *out,
+ int armored,
+ int cleartext,
+ int detached)
+{
+ const pgp_key_t *keypair;
+ const pgp_key_t *pubkey;
+ const unsigned overwrite = 1;
+ pgp_seckey_t *seckey;
+ const char *hashalg;
+ pgp_io_t *io;
+ char *numtries;
+ int attempts;
+ int ret;
+ int i;
+
+ io = netpgp->io;
+ if (f == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_sign_file: no filename specified\n");
+ return 0;
+ }
+ /* get key with which to sign */
+ if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
+ return 0;
+ }
+ ret = 1;
+ if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
+ (attempts = atoi(numtries)) <= 0) {
+ attempts = MAX_PASSPHRASE_ATTEMPTS;
+ } else if (strcmp(numtries, "unlimited") == 0) {
+ attempts = INFINITE_ATTEMPTS;
+ }
+ for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
+ if (netpgp->passfp == NULL) {
+ /* print out the user id */
+ pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
+ if (pubkey == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp: warning - using pubkey from secring\n");
+ pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
+ &keypair->key.seckey.pubkey, 0);
+ } else {
+ pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
+ &pubkey->key.pubkey, 0);
+ }
+ }
+ if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
+ /* now decrypt key */
+ seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
+ if (seckey == NULL) {
+ (void) fprintf(io->errs, "Bad passphrase\n");
+ }
+ } else {
+ pgp_keyring_t *secring;
+
+ secring = netpgp->secring;
+ seckey = &secring->keys[0].key.seckey;
+ }
+ }
+ if (seckey == NULL) {
+ (void) fprintf(io->errs, "Bad passphrase\n");
+ return 0;
+ }
+ /* sign file */
+ hashalg = netpgp_getvar(netpgp, "hash");
+ if (seckey->pubkey.alg == PGP_PKA_DSA) {
+ hashalg = "sha1";
+ }
+ if (detached) {
+ ret = pgp_sign_detached(io, f, out, seckey, hashalg,
+ get_birthtime(netpgp_getvar(netpgp, "birthtime")),
+ get_duration(netpgp_getvar(netpgp, "duration")),
+ (unsigned)armored,
+ overwrite);
+ } else {
+ ret = pgp_sign_file(io, f, out, seckey, hashalg,
+ get_birthtime(netpgp_getvar(netpgp, "birthtime")),
+ get_duration(netpgp_getvar(netpgp, "duration")),
+ (unsigned)armored, (unsigned)cleartext,
+ overwrite);
+ }
+ pgp_forget(seckey, (unsigned)sizeof(*seckey));
+ return ret;
+}
+
+#define ARMOR_SIG_HEAD "-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"
+
+/* verify a file */
+int
+netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
+{
+ pgp_validation_t result;
+ pgp_io_t *io;
+ unsigned realarmor;
+
+ __PGP_USED(armored);
+ (void) memset(&result, 0x0, sizeof(result));
+ io = netpgp->io;
+ if (in == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_verify_file: no filename specified\n");
+ return 0;
+ }
+ realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD);
+ if (pgp_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
+ resultp(io, in, &result, netpgp->pubring);
+ return 1;
+ }
+ if (result.validc + result.invalidc + result.unknownc == 0) {
+ (void) fprintf(io->errs,
+ "\"%s\": No signatures found - is this a signed file?\n",
+ in);
+ } else if (result.invalidc == 0 && result.unknownc == 0) {
+ (void) fprintf(io->errs,
+ "\"%s\": file verification failure: invalid signature time\n", in);
+ } else {
+ (void) fprintf(io->errs,
+"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
+ in, result.invalidc, result.unknownc);
+ }
+ return 0;
+}
+
+/* sign some memory */
+int
+netpgp_sign_memory(netpgp_t *netpgp,
+ const char *userid,
+ char *mem,
+ size_t size,
+ char *out,
+ size_t outsize,
+ const unsigned armored,
+ const unsigned cleartext)
+{
+ const pgp_key_t *keypair;
+ const pgp_key_t *pubkey;
+ pgp_seckey_t *seckey;
+ pgp_memory_t *signedmem;
+ const char *hashalg;
+ pgp_io_t *io;
+ char *numtries;
+ int attempts;
+ int ret;
+ int i;
+
+ io = netpgp->io;
+ if (mem == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_sign_memory: no memory to sign\n");
+ return 0;
+ }
+ if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
+ return 0;
+ }
+ ret = 1;
+ if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
+ (attempts = atoi(numtries)) <= 0) {
+ attempts = MAX_PASSPHRASE_ATTEMPTS;
+ } else if (strcmp(numtries, "unlimited") == 0) {
+ attempts = INFINITE_ATTEMPTS;
+ }
+ for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
+ if (netpgp->passfp == NULL) {
+ /* print out the user id */
+ pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
+ if (pubkey == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp: warning - using pubkey from secring\n");
+ pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
+ &keypair->key.seckey.pubkey, 0);
+ } else {
+ pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
+ &pubkey->key.pubkey, 0);
+ }
+ }
+ /* now decrypt key */
+ seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
+ if (seckey == NULL) {
+ (void) fprintf(io->errs, "Bad passphrase\n");
+ }
+ }
+ if (seckey == NULL) {
+ (void) fprintf(io->errs, "Bad passphrase\n");
+ return 0;
+ }
+ /* sign file */
+ (void) memset(out, 0x0, outsize);
+ hashalg = netpgp_getvar(netpgp, "hash");
+ if (seckey->pubkey.alg == PGP_PKA_DSA) {
+ hashalg = "sha1";
+ }
+ signedmem = pgp_sign_buf(io, mem, size, seckey,
+ get_birthtime(netpgp_getvar(netpgp, "birthtime")),
+ get_duration(netpgp_getvar(netpgp, "duration")),
+ hashalg, armored, cleartext);
+ if (signedmem) {
+ size_t m;
+
+ m = MIN(pgp_mem_len(signedmem), outsize);
+ (void) memcpy(out, pgp_mem_data(signedmem), m);
+ pgp_memory_free(signedmem);
+ ret = (int)m;
+ } else {
+ ret = 0;
+ }
+ pgp_forget(seckey, (unsigned)sizeof(*seckey));
+ return ret;
+}
+
+/* verify memory */
+int
+netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
+ void *out, size_t outsize, const int armored)
+{
+ pgp_validation_t result;
+ pgp_memory_t *signedmem;
+ pgp_memory_t *cat;
+ pgp_io_t *io;
+ size_t m;
+ int ret;
+
+ (void) memset(&result, 0x0, sizeof(result));
+ io = netpgp->io;
+ if (in == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_verify_memory: no memory to verify\n");
+ return 0;
+ }
+ signedmem = pgp_memory_new();
+ pgp_memory_add(signedmem, in, size);
+ if (out) {
+ cat = pgp_memory_new();
+ }
+ ret = pgp_validate_mem(io, &result, signedmem,
+ (out) ? &cat : NULL,
+ armored, netpgp->pubring);
+ /* signedmem is freed from pgp_validate_mem */
+ if (ret) {
+ resultp(io, "", &result, netpgp->pubring);
+ if (out) {
+ m = MIN(pgp_mem_len(cat), outsize);
+ (void) memcpy(out, pgp_mem_data(cat), m);
+ pgp_memory_free(cat);
+ } else {
+ m = 1;
+ }
+ return (int)m;
+ }
+ if (result.validc + result.invalidc + result.unknownc == 0) {
+ (void) fprintf(io->errs,
+ "No signatures found - is this memory signed?\n");
+ } else if (result.invalidc == 0 && result.unknownc == 0) {
+ (void) fprintf(io->errs,
+ "memory verification failure: invalid signature time\n");
+ } else {
+ (void) fprintf(io->errs,
+"memory verification failure: %u invalid signatures, %u unknown signatures\n",
+ result.invalidc, result.unknownc);
+ }
+ return 0;
+}
+
+/* encrypt some memory */
+int
+netpgp_encrypt_memory(netpgp_t *netpgp,
+ const char *userid,
+ void *in,
+ const size_t insize,
+ char *out,
+ size_t outsize,
+ int armored)
+{
+ const pgp_key_t *keypair;
+ pgp_memory_t *enc;
+ pgp_io_t *io;
+ size_t m;
+
+ io = netpgp->io;
+ if (in == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_encrypt_buf: no memory to encrypt\n");
+ return 0;
+ }
+ if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
+ return 0;
+ }
+ if (in == out) {
+ (void) fprintf(io->errs,
+ "netpgp_encrypt_buf: input and output bufs need to be different\n");
+ return 0;
+ }
+ if (outsize < insize) {
+ (void) fprintf(io->errs,
+ "netpgp_encrypt_buf: input size is larger than output size\n");
+ return 0;
+ }
+ enc = pgp_encrypt_buf(io, in, insize, keypair, (unsigned)armored,
+ netpgp_getvar(netpgp, "cipher"));
+ m = MIN(pgp_mem_len(enc), outsize);
+ (void) memcpy(out, pgp_mem_data(enc), m);
+ pgp_memory_free(enc);
+ return (int)m;
+}
+
+/* decrypt a chunk of memory */
+int
+netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
+ char *out, size_t outsize, const int armored)
+{
+ pgp_memory_t *mem;
+ pgp_io_t *io;
+ unsigned realarmour;
+ unsigned sshkeys;
+ size_t m;
+ char *numtries;
+ int attempts;
+
+ __PGP_USED(armored);
+ io = netpgp->io;
+ if (input == NULL) {
+ (void) fprintf(io->errs,
+ "netpgp_decrypt_memory: no memory\n");
+ return 0;
+ }
+ realarmour = isarmoured(io, NULL, input, ARMOR_HEAD);
+ sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
+ if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
+ (attempts = atoi(numtries)) <= 0) {
+ attempts = MAX_PASSPHRASE_ATTEMPTS;
+ } else if (strcmp(numtries, "unlimited") == 0) {
+ attempts = INFINITE_ATTEMPTS;
+ }
+ mem = pgp_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
+ netpgp->pubring,
+ realarmour, sshkeys,
+ netpgp->passfp,
+ attempts,
+ get_passphrase_cb);
+ if (mem == NULL) {
+ return -1;
+ }
+ m = MIN(pgp_mem_len(mem), outsize);
+ (void) memcpy(out, pgp_mem_data(mem), m);
+ pgp_memory_free(mem);
+ return (int)m;
+}
+
+/* wrappers for the ops_debug_level functions we added to openpgpsdk */
+
+/* set the debugging level per filename */
+int
+netpgp_set_debug(const char *f)
+{
+ return pgp_set_debug_level(f);
+}
+
+/* get the debugging level per filename */
+int
+netpgp_get_debug(const char *f)
+{
+ return pgp_get_debug_level(f);
+}
+
+/* return the version for the library */
+const char *
+netpgp_get_info(const char *type)
+{
+ return pgp_get_info(type);
+}
+
+/* list all the packets in a file */
+int
+netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
+{
+ pgp_keyring_t *keyring;
+ const unsigned noarmor = 0;
+ struct stat st;
+ pgp_io_t *io;
+ char ringname[MAXPATHLEN];
+ char *homedir;
+ int ret;
+
+ io = netpgp->io;
+ if (f == NULL) {
+ (void) fprintf(io->errs, "No file containing packets\n");
+ return 0;
+ }
+ if (stat(f, &st) < 0) {
+ (void) fprintf(io->errs, "No such file '%s'\n", f);
+ return 0;
+ }
+ homedir = netpgp_getvar(netpgp, "homedir");
+ if (pubringname == NULL) {
+ (void) snprintf(ringname, sizeof(ringname),
+ "%s/pubring.gpg", homedir);
+ pubringname = ringname;
+ }
+ if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
+ (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
+ return 0;
+ }
+ if (!pgp_keyring_fileread(keyring, noarmor, pubringname)) {
+ free(keyring);
+ (void) fprintf(io->errs, "Cannot read pub keyring %s\n",
+ pubringname);
+ return 0;
+ }
+ netpgp->pubring = keyring;
+ netpgp_setvar(netpgp, "pubring", pubringname);
+ ret = pgp_list_packets(io, f, (unsigned)armor,
+ netpgp->secring,
+ netpgp->pubring,
+ netpgp->passfp,
+ get_passphrase_cb);
+ free(keyring);
+ return ret;
+}
+
+/* set a variable */
+int
+netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
+{
+ char *newval;
+ int i;
+
+ /* protect against the case where 'value' is netpgp->value[i] */
+ newval = netpgp_strdup(value);
+ if ((i = findvar(netpgp, name)) < 0) {
+ /* add the element to the array */
+ if (size_arrays(netpgp, netpgp->size + 15)) {
+ netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
+ }
+ } else {
+ /* replace the element in the array */
+ if (netpgp->value[i]) {
+ free(netpgp->value[i]);
+ netpgp->value[i] = NULL;
+ }
+ }
+ /* sanity checks for range of values */
+ if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
+ if (pgp_str_to_hash_alg(newval) == PGP_HASH_UNKNOWN) {
+ free(newval);
+ return 0;
+ }
+ }
+ netpgp->value[i] = newval;
+ return 1;
+}
+
+/* unset a variable */
+int
+netpgp_unsetvar(netpgp_t *netpgp, const char *name)
+{
+ int i;
+
+ if ((i = findvar(netpgp, name)) >= 0) {
+ if (netpgp->value[i]) {
+ free(netpgp->value[i]);
+ netpgp->value[i] = NULL;
+ }
+ netpgp->value[i] = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+/* get a variable's value (NULL if not set) */
+char *
+netpgp_getvar(netpgp_t *netpgp, const char *name)
+{
+ int i;
+
+ return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
+}
+
+/* increment a value */
+int
+netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
+{
+ char *cp;
+ char num[16];
+ int val;
+
+ val = 0;
+ if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
+ val = atoi(cp);
+ }
+ (void) snprintf(num, sizeof(num), "%d", val + delta);
+ netpgp_setvar(netpgp, name, num);
+ return 1;
+}
+
+/* set the home directory value to "home/subdir" */
+int
+netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
+{
+ struct stat st;
+ char d[MAXPATHLEN];
+
+ if (home == NULL) {
+ if (!quiet) {
+ (void) fprintf(stderr, "NULL HOME directory\n");
+ }
+ return 0;
+ }
+ (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
+ if (stat(d, &st) == 0) {
+ if ((st.st_mode & S_IFMT) == S_IFDIR) {
+ netpgp_setvar(netpgp, "homedir", d);
+ return 1;
+ }
+ (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
+ d);
+ return 0;
+ }
+ if (!quiet) {
+ (void) fprintf(stderr,
+ "netpgp: warning homedir \"%s\" not found\n", d);
+ }
+ netpgp_setvar(netpgp, "homedir", d);
+ return 1;
+}
+
+/* validate all sigs in the pub keyring */
+int
+netpgp_validate_sigs(netpgp_t *netpgp)
+{
+ pgp_validation_t result;
+
+ return (int)pgp_validate_all_sigs(&result, netpgp->pubring, NULL);
+}
+
+/* print the json out on 'fp' */
+int
+netpgp_format_json(void *vp, const char *json, const int psigs)
+{
+ mj_t ids;
+ FILE *fp;
+ int from;
+ int idc;
+ int tok;
+ int to;
+ int i;
+
+ if ((fp = (FILE *)vp) == NULL || json == NULL) {
+ return 0;
+ }
+ /* ids is an array of strings, each containing 1 entry */
+ (void) memset(&ids, 0x0, sizeof(ids));
+ from = to = tok = 0;
+ /* convert from string into an mj structure */
+ (void) mj_parse(&ids, json, &from, &to, &tok);
+ if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
+ idc = 0;
+ }
+ (void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
+ for (i = 0 ; i < idc ; i++) {
+ format_json_key(fp, &ids.value.v[i], psigs);
+ }
+ /* clean up */
+ mj_delete(&ids);
+ return idc;
+}
+
+/* find a key in keyring, and write it in ssh format */
+int
+netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
+{
+ const pgp_key_t *key;
+ pgp_keyring_t *keyring;
+ pgp_io_t *io;
+ unsigned k;
+ size_t cc;
+ char f[MAXPATHLEN];
+
+ keyring = NULL;
+ io = NULL;
+ cc = 0;
+ if ((io = calloc(1, sizeof(pgp_io_t))) == NULL) {
+ (void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 1\n");
+ goto done;
+ }
+ io->outs = stdout;
+ io->errs = stderr;
+ io->res = stderr;
+ netpgp->io = io;
+ /* write new to temp file */
+ savepubkey(s, f, sizeof(f));
+ if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
+ (void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 2\n");
+ goto done;
+ }
+ if (!pgp_keyring_fileread(netpgp->pubring = keyring, 1, f)) {
+ (void) fprintf(stderr, "can't import key\n");
+ goto done;
+ }
+ /* get rsa key */
+ k = 0;
+ key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring, userid, &k);
+ if (key == NULL) {
+ (void) fprintf(stderr, "no key found for '%s'\n", userid);
+ goto done;
+ }
+ if (key->key.pubkey.alg != PGP_PKA_RSA) {
+ /* we're not interested in supporting DSA either :-) */
+ (void) fprintf(stderr, "key not RSA '%s'\n", userid);
+ goto done;
+ }
+ /* XXX - check trust sigs */
+ /* XXX - check expiry */
+ /* XXX - check start */
+ /* XXX - check not weak key */
+ /* get rsa e and n */
+ (void) memset(out, 0x0, size);
+ cc = formatstring((char *)out, (const uint8_t *)"ssh-rsa", 7);
+ cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.e);
+ cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.n);
+done:
+ if (io) {
+ free(io);
+ }
+ if (keyring) {
+ free(keyring);
+ }
+ return (int)cc;
+}
diff --git a/libs/netpgp/src/lib/netpgpdefs.h b/libs/netpgp/src/lib/netpgpdefs.h
new file mode 100644
index 00000000..37b2bf7f
--- /dev/null
+++ b/libs/netpgp/src/lib/netpgpdefs.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@netbsd.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NETPGPDEFS_H_
+#define NETPGPDEFS_H_ 1
+
+#define PRItime "ll"
+
+#ifdef WIN32
+#define PRIsize "I"
+#else
+#define PRIsize "z"
+#endif
+
+/* for silencing unused parameter warnings */
+#define __PGP_USED(x) /*LINTED*/(void)&(x)
+
+#ifndef __UNCONST
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif
+
+/* number of elements in an array */
+#define PGP_ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
+
+void hexdump(FILE *, const char *, const uint8_t *, size_t);
+
+const char *pgp_str_from_map(int, pgp_map_t *);
+
+int pgp_set_debug_level(const char *);
+int pgp_get_debug_level(const char *);
+
+void *pgp_new(size_t);
+
+#define NETPGP_BUFSIZ 8192
+
+#define CALLBACK(t, cbinfo, pkt) do { \
+ (pkt)->tag = (t); \
+ if (pgp_callback(pkt, cbinfo) == PGP_RELEASE_MEMORY) { \
+ pgp_parser_content_free(pkt); \
+ } \
+} while(/* CONSTCOND */0)
+
+#endif /* !NETPGPDEFS_H_ */
diff --git a/libs/netpgp/src/lib/netpgpdigest.h b/libs/netpgp/src/lib/netpgpdigest.h
new file mode 100644
index 00000000..3b15a25b
--- /dev/null
+++ b/libs/netpgp/src/lib/netpgpdigest.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@netbsd.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NETPGPDIGEST_H_
+#define NETPGPDIGEST_H_
+
+/* header file to define the sizes for various digest arrays */
+
+#ifdef HAVE_OPENSSL_MD5_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_SHA_H
+#include
+#endif
+
+/* Apple */
+#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
+#undef MD5_DIGEST_LENGTH
+#undef SHA_DIGEST_LENGTH
+#define COMMON_DIGEST_FOR_OPENSSL 1
+#include
+#endif
+
+/* SHA1 Hash Size */
+#define PGP_SHA1_HASH_SIZE SHA_DIGEST_LENGTH
+#define PGP_SHA256_HASH_SIZE SHA256_DIGEST_LENGTH
+#define PGP_CHECKHASH_SIZE PGP_SHA1_HASH_SIZE
+
+#endif /* NETPGPDIGEST_H_ */
diff --git a/libs/netpgp/src/lib/netpgpsdk.h b/libs/netpgp/src/lib/netpgpsdk.h
new file mode 100644
index 00000000..560a6436
--- /dev/null
+++ b/libs/netpgp/src/lib/netpgpsdk.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2009,2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NETPGPSDK_H_
+#define NETPGPSDK_H_
+
+#include "keyring.h"
+#include "crypto.h"
+#include "signature.h"
+#include "packet-show.h"
+
+#ifndef __printflike
+#define __printflike(n, m) __attribute__((format(printf,n,m)))
+#endif
+
+typedef struct pgp_validation_t {
+ unsigned validc;
+ pgp_sig_info_t *valid_sigs;
+ unsigned invalidc;
+ pgp_sig_info_t *invalid_sigs;
+ unsigned unknownc;
+ pgp_sig_info_t *unknown_sigs;
+ time_t birthtime;
+ time_t duration;
+} pgp_validation_t;
+
+void pgp_validate_result_free(pgp_validation_t *);
+
+unsigned
+pgp_validate_key_sigs(pgp_validation_t *,
+ const pgp_key_t *,
+ const pgp_keyring_t *,
+ pgp_cb_ret_t cb(const pgp_packet_t *, pgp_cbdata_t *));
+
+unsigned
+pgp_validate_all_sigs(pgp_validation_t *,
+ const pgp_keyring_t *,
+ pgp_cb_ret_t cb(const pgp_packet_t *, pgp_cbdata_t *));
+
+unsigned pgp_check_sig(const uint8_t *,
+ unsigned, const pgp_sig_t *, const pgp_pubkey_t *);
+
+const char *pgp_get_info(const char *type);
+
+int pgp_asprintf(char **, const char *, ...) __printflike(2, 3);
+
+void netpgp_log(const char *, ...) __printflike(1, 2);
+
+int netpgp_strcasecmp(const char *, const char *);
+char *netpgp_strdup(const char *);
+
+
+#endif
diff --git a/libs/netpgp/src/lib/openssl_crypto.c b/libs/netpgp/src/lib/openssl_crypto.c
new file mode 100644
index 00000000..ff25d459
--- /dev/null
+++ b/libs/netpgp/src/lib/openssl_crypto.c
@@ -0,0 +1,1050 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: openssl_crypto.c,v 1.33 2010/11/07 08:39:59 agc Exp $");
+#endif
+
+#ifdef HAVE_OPENSSL_DSA_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_RSA_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_ERR_H
+#include
+#endif
+
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#include "crypto.h"
+#include "keyring.h"
+#include "readerwriter.h"
+#include "netpgpdefs.h"
+#include "netpgpdigest.h"
+#include "packet.h"
+
+
+static void
+test_seckey(const pgp_seckey_t *seckey)
+{
+ RSA *test = RSA_new();
+
+ test->n = BN_dup(seckey->pubkey.key.rsa.n);
+ test->e = BN_dup(seckey->pubkey.key.rsa.e);
+
+ test->d = BN_dup(seckey->key.rsa.d);
+ test->p = BN_dup(seckey->key.rsa.p);
+ test->q = BN_dup(seckey->key.rsa.q);
+
+ if (RSA_check_key(test) != 1) {
+ (void) fprintf(stderr,
+ "test_seckey: RSA_check_key failed\n");
+ }
+ RSA_free(test);
+}
+
+static int
+md5_init(pgp_hash_t *hash)
+{
+ if (hash->data) {
+ (void) fprintf(stderr, "md5_init: hash data non-null\n");
+ }
+ if ((hash->data = calloc(1, sizeof(MD5_CTX))) == NULL) {
+ (void) fprintf(stderr, "md5_init: bad alloc\n");
+ return 0;
+ }
+ MD5_Init(hash->data);
+ return 1;
+}
+
+static void
+md5_add(pgp_hash_t *hash, const uint8_t *data, unsigned length)
+{
+ MD5_Update(hash->data, data, length);
+}
+
+static unsigned
+md5_finish(pgp_hash_t *hash, uint8_t *out)
+{
+ MD5_Final(out, hash->data);
+ free(hash->data);
+ hash->data = NULL;
+ return 16;
+}
+
+static const pgp_hash_t md5 = {
+ PGP_HASH_MD5,
+ MD5_DIGEST_LENGTH,
+ "MD5",
+ md5_init,
+ md5_add,
+ md5_finish,
+ NULL
+};
+
+/**
+ \ingroup Core_Crypto
+ \brief Initialise to MD5
+ \param hash Hash to initialise
+*/
+void
+pgp_hash_md5(pgp_hash_t *hash)
+{
+ *hash = md5;
+}
+
+static int
+sha1_init(pgp_hash_t *hash)
+{
+ if (hash->data) {
+ (void) fprintf(stderr, "sha1_init: hash data non-null\n");
+ }
+ if ((hash->data = calloc(1, sizeof(SHA_CTX))) == NULL) {
+ (void) fprintf(stderr, "sha1_init: bad alloc\n");
+ return 0;
+ }
+ SHA1_Init(hash->data);
+ return 1;
+}
+
+static void
+sha1_add(pgp_hash_t *hash, const uint8_t *data, unsigned length)
+{
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha1_add", data, length);
+ }
+ SHA1_Update(hash->data, data, length);
+}
+
+static unsigned
+sha1_finish(pgp_hash_t *hash, uint8_t *out)
+{
+ SHA1_Final(out, hash->data);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha1_finish", out, PGP_SHA1_HASH_SIZE);
+ }
+ free(hash->data);
+ hash->data = NULL;
+ return PGP_SHA1_HASH_SIZE;
+}
+
+static const pgp_hash_t sha1 = {
+ PGP_HASH_SHA1,
+ PGP_SHA1_HASH_SIZE,
+ "SHA1",
+ sha1_init,
+ sha1_add,
+ sha1_finish,
+ NULL
+};
+
+/**
+ \ingroup Core_Crypto
+ \brief Initialise to SHA1
+ \param hash Hash to initialise
+*/
+void
+pgp_hash_sha1(pgp_hash_t *hash)
+{
+ *hash = sha1;
+}
+
+static int
+sha256_init(pgp_hash_t *hash)
+{
+ if (hash->data) {
+ (void) fprintf(stderr, "sha256_init: hash data non-null\n");
+ }
+ if ((hash->data = calloc(1, sizeof(SHA256_CTX))) == NULL) {
+ (void) fprintf(stderr, "sha256_init: bad alloc\n");
+ return 0;
+ }
+ SHA256_Init(hash->data);
+ return 1;
+}
+
+static void
+sha256_add(pgp_hash_t *hash, const uint8_t *data, unsigned length)
+{
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha256_add", data, length);
+ }
+ SHA256_Update(hash->data, data, length);
+}
+
+static unsigned
+sha256_finish(pgp_hash_t *hash, uint8_t *out)
+{
+ SHA256_Final(out, hash->data);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha1_finish", out, SHA256_DIGEST_LENGTH);
+ }
+ free(hash->data);
+ hash->data = NULL;
+ return SHA256_DIGEST_LENGTH;
+}
+
+static const pgp_hash_t sha256 = {
+ PGP_HASH_SHA256,
+ SHA256_DIGEST_LENGTH,
+ "SHA256",
+ sha256_init,
+ sha256_add,
+ sha256_finish,
+ NULL
+};
+
+void
+pgp_hash_sha256(pgp_hash_t *hash)
+{
+ *hash = sha256;
+}
+
+/*
+ * SHA384
+ */
+static int
+sha384_init(pgp_hash_t *hash)
+{
+ if (hash->data) {
+ (void) fprintf(stderr, "sha384_init: hash data non-null\n");
+ }
+ if ((hash->data = calloc(1, sizeof(SHA512_CTX))) == NULL) {
+ (void) fprintf(stderr, "sha384_init: bad alloc\n");
+ return 0;
+ }
+ SHA384_Init(hash->data);
+ return 1;
+}
+
+static void
+sha384_add(pgp_hash_t *hash, const uint8_t *data, unsigned length)
+{
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha384_add", data, length);
+ }
+ SHA384_Update(hash->data, data, length);
+}
+
+static unsigned
+sha384_finish(pgp_hash_t *hash, uint8_t *out)
+{
+ SHA384_Final(out, hash->data);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha384_finish", out, SHA384_DIGEST_LENGTH);
+ }
+ free(hash->data);
+ hash->data = NULL;
+ return SHA384_DIGEST_LENGTH;
+}
+
+static const pgp_hash_t sha384 = {
+ PGP_HASH_SHA384,
+ SHA384_DIGEST_LENGTH,
+ "SHA384",
+ sha384_init,
+ sha384_add,
+ sha384_finish,
+ NULL
+};
+
+void
+pgp_hash_sha384(pgp_hash_t *hash)
+{
+ *hash = sha384;
+}
+
+/*
+ * SHA512
+ */
+static int
+sha512_init(pgp_hash_t *hash)
+{
+ if (hash->data) {
+ (void) fprintf(stderr, "sha512_init: hash data non-null\n");
+ }
+ if ((hash->data = calloc(1, sizeof(SHA512_CTX))) == NULL) {
+ (void) fprintf(stderr, "sha512_init: bad alloc\n");
+ return 0;
+ }
+ SHA512_Init(hash->data);
+ return 1;
+}
+
+static void
+sha512_add(pgp_hash_t *hash, const uint8_t *data, unsigned length)
+{
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha512_add", data, length);
+ }
+ SHA512_Update(hash->data, data, length);
+}
+
+static unsigned
+sha512_finish(pgp_hash_t *hash, uint8_t *out)
+{
+ SHA512_Final(out, hash->data);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha512_finish", out, SHA512_DIGEST_LENGTH);
+ }
+ free(hash->data);
+ hash->data = NULL;
+ return SHA512_DIGEST_LENGTH;
+}
+
+static const pgp_hash_t sha512 = {
+ PGP_HASH_SHA512,
+ SHA512_DIGEST_LENGTH,
+ "SHA512",
+ sha512_init,
+ sha512_add,
+ sha512_finish,
+ NULL
+};
+
+void
+pgp_hash_sha512(pgp_hash_t *hash)
+{
+ *hash = sha512;
+}
+
+/*
+ * SHA224
+ */
+
+static int
+sha224_init(pgp_hash_t *hash)
+{
+ if (hash->data) {
+ (void) fprintf(stderr, "sha224_init: hash data non-null\n");
+ }
+ if ((hash->data = calloc(1, sizeof(SHA256_CTX))) == NULL) {
+ (void) fprintf(stderr, "sha256_init: bad alloc\n");
+ return 0;
+ }
+ SHA224_Init(hash->data);
+ return 1;
+}
+
+static void
+sha224_add(pgp_hash_t *hash, const uint8_t *data, unsigned length)
+{
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha224_add", data, length);
+ }
+ SHA224_Update(hash->data, data, length);
+}
+
+static unsigned
+sha224_finish(pgp_hash_t *hash, uint8_t *out)
+{
+ SHA224_Final(out, hash->data);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sha224_finish", out, SHA224_DIGEST_LENGTH);
+ }
+ free(hash->data);
+ hash->data = NULL;
+ return SHA224_DIGEST_LENGTH;
+}
+
+static const pgp_hash_t sha224 = {
+ PGP_HASH_SHA224,
+ SHA224_DIGEST_LENGTH,
+ "SHA224",
+ sha224_init,
+ sha224_add,
+ sha224_finish,
+ NULL
+};
+
+void
+pgp_hash_sha224(pgp_hash_t *hash)
+{
+ *hash = sha224;
+}
+
+unsigned
+pgp_dsa_verify(const uint8_t *hash, size_t hash_length,
+ const pgp_dsa_sig_t *sig,
+ const pgp_dsa_pubkey_t *dsa)
+{
+ unsigned qlen;
+ DSA_SIG *osig;
+ DSA *odsa;
+ int ret;
+
+ osig = DSA_SIG_new();
+ osig->r = sig->r;
+ osig->s = sig->s;
+
+ odsa = DSA_new();
+ odsa->p = dsa->p;
+ odsa->q = dsa->q;
+ odsa->g = dsa->g;
+ odsa->pub_key = dsa->y;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "input hash", hash, hash_length);
+ (void) fprintf(stderr, "Q=%d\n", BN_num_bytes(odsa->q));
+ }
+ if ((qlen = (unsigned)BN_num_bytes(odsa->q)) < hash_length) {
+ hash_length = qlen;
+ }
+ ret = DSA_do_verify(hash, (int)hash_length, osig, odsa);
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "ret=%d\n", ret);
+ }
+ if (ret < 0) {
+ (void) fprintf(stderr, "pgp_dsa_verify: DSA verification\n");
+ return 0;
+ }
+
+ odsa->p = odsa->q = odsa->g = odsa->pub_key = NULL;
+ DSA_free(odsa);
+
+ osig->r = osig->s = NULL;
+ DSA_SIG_free(osig);
+
+ return (unsigned)ret;
+}
+
+/**
+ \ingroup Core_Crypto
+ \brief Recovers message digest from the signature
+ \param out Where to write decrypted data to
+ \param in Encrypted data
+ \param length Length of encrypted data
+ \param pubkey RSA public key
+ \return size of recovered message digest
+*/
+int
+pgp_rsa_public_decrypt(uint8_t *out,
+ const uint8_t *in,
+ size_t length,
+ const pgp_rsa_pubkey_t *pubkey)
+{
+ RSA *orsa;
+ int n;
+
+ orsa = RSA_new();
+ orsa->n = pubkey->n;
+ orsa->e = pubkey->e;
+
+ n = RSA_public_decrypt((int)length, in, out, orsa, RSA_NO_PADDING);
+
+ orsa->n = orsa->e = NULL;
+ RSA_free(orsa);
+
+ return n;
+}
+
+/**
+ \ingroup Core_Crypto
+ \brief Signs data with RSA
+ \param out Where to write signature
+ \param in Data to sign
+ \param length Length of data
+ \param seckey RSA secret key
+ \param pubkey RSA public key
+ \return number of bytes decrypted
+*/
+int
+pgp_rsa_private_encrypt(uint8_t *out,
+ const uint8_t *in,
+ size_t length,
+ const pgp_rsa_seckey_t *seckey,
+ const pgp_rsa_pubkey_t *pubkey)
+{
+ RSA *orsa;
+ int n;
+
+ orsa = RSA_new();
+ orsa->n = BN_dup(pubkey->n);
+ orsa->d = seckey->d;
+ orsa->p = seckey->q; /* p and q are round the other way in openssl */
+ orsa->q = seckey->p;
+
+ /* debug */
+ orsa->e = BN_dup(pubkey->e);
+ /* If this isn't set, it's very likely that the programmer hasn't */
+ /* decrypted the secret key. RSA_check_key segfaults in that case. */
+ /* Use pgp_decrypt_seckey() to do that. */
+ if (orsa->d == NULL) {
+ (void) fprintf(stderr, "orsa is not set\n");
+ return 0;
+ }
+ if (RSA_check_key(orsa) != 1) {
+ (void) fprintf(stderr, "RSA_check_key is not set\n");
+ return 0;
+ }
+ /* end debug */
+
+ n = RSA_private_encrypt((int)length, in, out, orsa, RSA_NO_PADDING);
+
+ orsa->n = orsa->d = orsa->p = orsa->q = NULL;
+ RSA_free(orsa);
+
+ return n;
+}
+
+/**
+\ingroup Core_Crypto
+\brief Decrypts RSA-encrypted data
+\param out Where to write the plaintext
+\param in Encrypted data
+\param length Length of encrypted data
+\param seckey RSA secret key
+\param pubkey RSA public key
+\return size of recovered plaintext
+*/
+int
+pgp_rsa_private_decrypt(uint8_t *out,
+ const uint8_t *in,
+ size_t length,
+ const pgp_rsa_seckey_t *seckey,
+ const pgp_rsa_pubkey_t *pubkey)
+{
+ RSA *keypair;
+ int n;
+ char errbuf[1024];
+
+ keypair = RSA_new();
+ keypair->n = pubkey->n; /* XXX: do we need n? */
+ keypair->d = seckey->d;
+ keypair->p = seckey->q;
+ keypair->q = seckey->p;
+
+ /* debug */
+ keypair->e = pubkey->e;
+ if (RSA_check_key(keypair) != 1) {
+ (void) fprintf(stderr, "RSA_check_key is not set\n");
+ return 0;
+ }
+ /* end debug */
+
+ n = RSA_private_decrypt((int)length, in, out, keypair, RSA_NO_PADDING);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("pgp_rsa_private_decrypt: n=%d\n",n);
+ }
+
+ errbuf[0] = '\0';
+ if (n == -1) {
+ unsigned long err = ERR_get_error();
+
+ ERR_error_string(err, &errbuf[0]);
+ (void) fprintf(stderr, "openssl error : %s\n", errbuf);
+ }
+ keypair->n = keypair->d = keypair->p = keypair->q = NULL;
+ RSA_free(keypair);
+
+ return n;
+}
+
+/**
+ \ingroup Core_Crypto
+ \brief RSA-encrypts data
+ \param out Where to write the encrypted data
+ \param in Plaintext
+ \param length Size of plaintext
+ \param pubkey RSA Public Key
+*/
+int
+pgp_rsa_public_encrypt(uint8_t *out,
+ const uint8_t *in,
+ size_t length,
+ const pgp_rsa_pubkey_t *pubkey)
+{
+ RSA *orsa;
+ int n;
+
+ /* printf("pgp_rsa_public_encrypt: length=%ld\n", length); */
+
+ orsa = RSA_new();
+ orsa->n = pubkey->n;
+ orsa->e = pubkey->e;
+
+ /* printf("len: %ld\n", length); */
+ /* pgp_print_bn("n: ", orsa->n); */
+ /* pgp_print_bn("e: ", orsa->e); */
+ n = RSA_public_encrypt((int)length, in, out, orsa, RSA_NO_PADDING);
+
+ if (n == -1) {
+ BIO *fd_out;
+
+ fd_out = BIO_new_fd(fileno(stderr), BIO_NOCLOSE);
+ ERR_print_errors(fd_out);
+ }
+ orsa->n = orsa->e = NULL;
+ RSA_free(orsa);
+
+ return n;
+}
+
+/**
+ \ingroup Core_Crypto
+ \brief Finalise openssl
+ \note Would usually call pgp_finish() instead
+ \sa pgp_finish()
+*/
+void
+pgp_crypto_finish(void)
+{
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_state((unsigned long)0);
+}
+
+/**
+ \ingroup Core_Hashes
+ \brief Get Hash name
+ \param hash Hash struct
+ \return Hash name
+*/
+const char *
+pgp_text_from_hash(pgp_hash_t *hash)
+{
+ return hash->name;
+}
+
+/**
+ \ingroup HighLevel_KeyGenerate
+ \brief Generates an RSA keypair
+ \param numbits Modulus size
+ \param e Public Exponent
+ \param keydata Pointer to keydata struct to hold new key
+ \return 1 if key generated successfully; otherwise 0
+ \note It is the caller's responsibility to call pgp_keydata_free(keydata)
+*/
+static unsigned
+rsa_generate_keypair(pgp_key_t *keydata,
+ const int numbits,
+ const unsigned long e,
+ const char *hashalg,
+ const char *cipher)
+{
+ pgp_seckey_t *seckey;
+ RSA *rsa;
+ BN_CTX *ctx;
+ pgp_output_t *output;
+ pgp_memory_t *mem;
+
+ ctx = BN_CTX_new();
+ pgp_keydata_init(keydata, PGP_PTAG_CT_SECRET_KEY);
+ seckey = pgp_get_writable_seckey(keydata);
+
+ /* generate the key pair */
+
+ rsa = RSA_generate_key(numbits, e, NULL, NULL);
+
+ /* populate pgp key from ssl key */
+
+ seckey->pubkey.version = PGP_V4;
+ seckey->pubkey.birthtime = time(NULL);
+ seckey->pubkey.days_valid = 0;
+ seckey->pubkey.alg = PGP_PKA_RSA;
+
+ seckey->pubkey.key.rsa.n = BN_dup(rsa->n);
+ seckey->pubkey.key.rsa.e = BN_dup(rsa->e);
+
+ seckey->s2k_usage = PGP_S2KU_ENCRYPTED_AND_HASHED;
+ seckey->s2k_specifier = PGP_S2KS_SALTED;
+ /* seckey->s2k_specifier=PGP_S2KS_SIMPLE; */
+ if ((seckey->hash_alg = pgp_str_to_hash_alg(hashalg)) == PGP_HASH_UNKNOWN) {
+ seckey->hash_alg = PGP_HASH_SHA1;
+ }
+ seckey->alg = pgp_str_to_cipher(cipher);
+ seckey->octetc = 0;
+ seckey->checksum = 0;
+
+ seckey->key.rsa.d = BN_dup(rsa->d);
+ seckey->key.rsa.p = BN_dup(rsa->p);
+ seckey->key.rsa.q = BN_dup(rsa->q);
+ seckey->key.rsa.u = BN_mod_inverse(NULL, rsa->p, rsa->q, ctx);
+ if (seckey->key.rsa.u == NULL) {
+ (void) fprintf(stderr, "seckey->key.rsa.u is NULL\n");
+ return 0;
+ }
+ BN_CTX_free(ctx);
+
+ RSA_free(rsa);
+
+ pgp_keyid(keydata->sigid, PGP_KEY_ID_SIZE, &keydata->key.seckey.pubkey, seckey->hash_alg);
+ pgp_fingerprint(&keydata->sigfingerprint, &keydata->key.seckey.pubkey, seckey->hash_alg);
+
+ /* Generate checksum */
+
+ output = NULL;
+ mem = NULL;
+
+ pgp_setup_memory_write(&output, &mem, 128);
+
+ pgp_push_checksum_writer(output, seckey);
+
+ switch (seckey->pubkey.alg) {
+ case PGP_PKA_DSA:
+ return pgp_write_mpi(output, seckey->key.dsa.x);
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (!pgp_write_mpi(output, seckey->key.rsa.d) ||
+ !pgp_write_mpi(output, seckey->key.rsa.p) ||
+ !pgp_write_mpi(output, seckey->key.rsa.q) ||
+ !pgp_write_mpi(output, seckey->key.rsa.u)) {
+ return 0;
+ }
+ break;
+ case PGP_PKA_ELGAMAL:
+ return pgp_write_mpi(output, seckey->key.elgamal.x);
+
+ default:
+ (void) fprintf(stderr, "Bad seckey->pubkey.alg\n");
+ return 0;
+ }
+
+ /* close rather than pop, since its the only one on the stack */
+ pgp_writer_close(output);
+ pgp_teardown_memory_write(output, mem);
+
+ /* should now have checksum in seckey struct */
+
+ /* test */
+ if (pgp_get_debug_level(__FILE__)) {
+ test_seckey(seckey);
+ }
+
+ return 1;
+}
+
+/**
+ \ingroup HighLevel_KeyGenerate
+ \brief Creates a self-signed RSA keypair
+ \param numbits Modulus size
+ \param e Public Exponent
+ \param userid User ID
+ \return The new keypair or NULL
+
+ \note It is the caller's responsibility to call pgp_keydata_free(keydata)
+ \sa rsa_generate_keypair()
+ \sa pgp_keydata_free()
+*/
+pgp_key_t *
+pgp_rsa_new_selfsign_key(const int numbits,
+ const unsigned long e,
+ uint8_t *userid,
+ const char *hashalg,
+ const char *cipher)
+{
+ pgp_key_t *keydata;
+
+ keydata = pgp_keydata_new();
+ if (!rsa_generate_keypair(keydata, numbits, e, hashalg, cipher) ||
+ !pgp_add_selfsigned_userid(keydata, userid)) {
+ pgp_keydata_free(keydata);
+ return NULL;
+ }
+ return keydata;
+}
+
+DSA_SIG *
+pgp_dsa_sign(uint8_t *hashbuf,
+ unsigned hashsize,
+ const pgp_dsa_seckey_t *secdsa,
+ const pgp_dsa_pubkey_t *pubdsa)
+{
+ DSA_SIG *dsasig;
+ DSA *odsa;
+
+ odsa = DSA_new();
+ odsa->p = pubdsa->p;
+ odsa->q = pubdsa->q;
+ odsa->g = pubdsa->g;
+ odsa->pub_key = pubdsa->y;
+ odsa->priv_key = secdsa->x;
+
+ dsasig = DSA_do_sign(hashbuf, (int)hashsize, odsa);
+
+ odsa->p = odsa->q = odsa->g = odsa->pub_key = odsa->priv_key = NULL;
+ DSA_free(odsa);
+
+ return dsasig;
+}
+
+int
+openssl_read_pem_seckey(const char *f, pgp_key_t *key, const char *type, int verbose)
+{
+ FILE *fp;
+ char prompt[BUFSIZ];
+ char *pass;
+ DSA *dsa;
+ RSA *rsa;
+ int ok;
+
+ OpenSSL_add_all_algorithms();
+ if ((fp = fopen(f, "r")) == NULL) {
+ if (verbose) {
+ (void) fprintf(stderr, "can't open '%s'\n", f);
+ }
+ return 0;
+ }
+ ok = 1;
+ if (strcmp(type, "ssh-rsa") == 0) {
+ if ((rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) {
+ (void) snprintf(prompt, sizeof(prompt), "netpgp PEM %s passphrase: ", f);
+ do {
+ pass = getpass(prompt);
+ rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, pass);
+ } while (rsa == NULL);
+ }
+ key->key.seckey.key.rsa.d = rsa->d;
+ key->key.seckey.key.rsa.p = rsa->p;
+ key->key.seckey.key.rsa.q = rsa->q;
+ key->key.seckey.key.rsa.d = rsa->d;
+ } else if (strcmp(type, "ssh-dss") == 0) {
+ if ((dsa = PEM_read_DSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) {
+ ok = 0;
+ } else {
+ key->key.seckey.key.dsa.x = dsa->priv_key;
+ }
+ } else {
+ ok = 0;
+ }
+ (void) fclose(fp);
+ return ok;
+}
+
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'. Following
+ * algorihm hovers 10-70 bits above gpg values. And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow. It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+ return (p_bits <= 5120) ? p_bits / 10 + 160 : (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+pgp_elgamal_public_encrypt(uint8_t *g_to_k, uint8_t *encm,
+ const uint8_t *in,
+ size_t size,
+ const pgp_elgamal_pubkey_t *pubkey)
+{
+ int ret = 0;
+ int k_bits;
+ BIGNUM *m;
+ BIGNUM *p;
+ BIGNUM *g;
+ BIGNUM *y;
+ BIGNUM *k;
+ BIGNUM *yk;
+ BIGNUM *c1;
+ BIGNUM *c2;
+ BN_CTX *tmp;
+
+ m = BN_bin2bn(in, (int)size, NULL);
+ p = pubkey->p;
+ g = pubkey->g;
+ y = pubkey->y;
+ k = BN_new();
+ yk = BN_new();
+ c1 = BN_new();
+ c2 = BN_new();
+ tmp = BN_CTX_new();
+ if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp) {
+ goto done;
+ }
+ /*
+ * generate k
+ */
+ k_bits = decide_k_bits(BN_num_bits(p));
+ if (!BN_rand(k, k_bits, 0, 0)) {
+ goto done;
+ }
+ /*
+ * c1 = g^k c2 = m * y^k
+ */
+ if (!BN_mod_exp(c1, g, k, p, tmp)) {
+ goto done;
+ }
+ if (!BN_mod_exp(yk, y, k, p, tmp)) {
+ goto done;
+ }
+ if (!BN_mod_mul(c2, m, yk, p, tmp)) {
+ goto done;
+ }
+ /* result */
+ BN_bn2bin(c1, g_to_k);
+ ret = BN_num_bytes(c1); /* c1 = g^k */
+ BN_bn2bin(c2, encm);
+ ret += BN_num_bytes(c2); /* c2 = m * y^k */
+done:
+ if (tmp) {
+ BN_CTX_free(tmp);
+ }
+ if (c2) {
+ BN_clear_free(c2);
+ }
+ if (c1) {
+ BN_clear_free(c1);
+ }
+ if (yk) {
+ BN_clear_free(yk);
+ }
+ if (k) {
+ BN_clear_free(k);
+ }
+ if (g) {
+ BN_clear_free(g);
+ }
+ return ret;
+}
+
+int
+pgp_elgamal_private_decrypt(uint8_t *out,
+ const uint8_t *g_to_k,
+ const uint8_t *in,
+ size_t length,
+ const pgp_elgamal_seckey_t *seckey,
+ const pgp_elgamal_pubkey_t *pubkey)
+{
+ BIGNUM *bndiv;
+ BIGNUM *c1x;
+ BN_CTX *tmp;
+ BIGNUM *c1;
+ BIGNUM *c2;
+ BIGNUM *p;
+ BIGNUM *x;
+ BIGNUM *m;
+ int ret;
+
+ ret = 0;
+ /* c1 and c2 are in g_to_k and in, respectively*/
+ c1 = BN_bin2bn(g_to_k, (int)length, NULL);
+ c2 = BN_bin2bn(in, (int)length, NULL);
+ /* other bits */
+ p = pubkey->p;
+ x = seckey->x;
+ c1x = BN_new();
+ bndiv = BN_new();
+ m = BN_new();
+ tmp = BN_CTX_new();
+ if (!c1 || !c2 || !p || !x || !c1x || !bndiv || !m || !tmp) {
+ goto done;
+ }
+ /*
+ * m = c2 / (c1^x)
+ */
+ if (!BN_mod_exp(c1x, c1, x, p, tmp)) {
+ goto done;
+ }
+ if (!BN_mod_inverse(bndiv, c1x, p, tmp)) {
+ goto done;
+ }
+ if (!BN_mod_mul(m, c2, bndiv, p, tmp)) {
+ goto done;
+ }
+ /* result */
+ ret = BN_bn2bin(m, out);
+done:
+ if (tmp) {
+ BN_CTX_free(tmp);
+ }
+ if (m) {
+ BN_clear_free(m);
+ }
+ if (bndiv) {
+ BN_clear_free(bndiv);
+ }
+ if (c1x) {
+ BN_clear_free(c1x);
+ }
+ if (x) {
+ BN_clear_free(x);
+ }
+ if (p) {
+ BN_clear_free(p);
+ }
+ if (c1) {
+ BN_clear_free(c1);
+ }
+ if (c2) {
+ BN_clear_free(c2);
+ }
+ return ret;
+}
diff --git a/libs/netpgp/src/lib/packet-parse.c b/libs/netpgp/src/lib/packet-parse.c
new file mode 100644
index 00000000..bf85c311
--- /dev/null
+++ b/libs/netpgp/src/lib/packet-parse.c
@@ -0,0 +1,3468 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ * \brief Parser for OpenPGP packets
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: packet-parse.c,v 1.51 2012/03/05 02:20:18 christos Exp $");
+#endif
+
+#include
+#include
+
+#ifdef HAVE_OPENSSL_CAST_H
+#include
+#endif
+
+#include
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include
+#endif
+
+#include "packet.h"
+#include "packet-parse.h"
+#include "keyring.h"
+#include "errors.h"
+#include "packet-show.h"
+#include "create.h"
+#include "readerwriter.h"
+#include "netpgpdefs.h"
+#include "crypto.h"
+#include "netpgpdigest.h"
+
+#define ERRP(cbinfo, cont, err) do { \
+ cont.u.error = err; \
+ CALLBACK(PGP_PARSER_ERROR, cbinfo, &cont); \
+ return 0; \
+ /*NOTREACHED*/ \
+} while(/*CONSTCOND*/0)
+
+/**
+ * limread_data reads the specified amount of the subregion's data
+ * into a data_t structure
+ *
+ * \param data Empty structure which will be filled with data
+ * \param len Number of octets to read
+ * \param subregion
+ * \param stream How to parse
+ *
+ * \return 1 on success, 0 on failure
+ */
+static int
+limread_data(pgp_data_t *data, unsigned len,
+ pgp_region_t *subregion, pgp_stream_t *stream)
+{
+ data->len = len;
+
+ if (subregion->length - subregion->readc < len) {
+ (void) fprintf(stderr, "limread_data: bad length\n");
+ return 0;
+ }
+
+ data->contents = calloc(1, data->len);
+ if (!data->contents) {
+ return 0;
+ }
+
+ return pgp_limited_read(stream, data->contents, data->len, subregion,
+ &stream->errors, &stream->readinfo, &stream->cbinfo);
+}
+
+/**
+ * read_data reads the remainder of the subregion's data
+ * into a data_t structure
+ *
+ * \param data
+ * \param subregion
+ * \param stream
+ *
+ * \return 1 on success, 0 on failure
+ */
+static int
+read_data(pgp_data_t *data, pgp_region_t *region, pgp_stream_t *stream)
+{
+ int cc;
+
+ cc = region->length - region->readc;
+ return (cc >= 0) ? limread_data(data, (unsigned)cc, region, stream) : 0;
+}
+
+/**
+ * Reads the remainder of the subregion as a string.
+ * It is the user's responsibility to free the memory allocated here.
+ */
+
+static int
+read_unsig_str(uint8_t **str, pgp_region_t *subregion,
+ pgp_stream_t *stream)
+{
+ size_t len;
+
+ len = subregion->length - subregion->readc;
+ if ((*str = calloc(1, len + 1)) == NULL) {
+ return 0;
+ }
+ if (len &&
+ !pgp_limited_read(stream, *str, len, subregion, &stream->errors,
+ &stream->readinfo, &stream->cbinfo)) {
+ return 0;
+ }
+ (*str)[len] = '\0';
+ return 1;
+}
+
+static int
+read_string(char **str, pgp_region_t *subregion, pgp_stream_t *stream)
+{
+ return read_unsig_str((uint8_t **) str, subregion, stream);
+}
+
+void
+pgp_init_subregion(pgp_region_t *subregion, pgp_region_t *region)
+{
+ (void) memset(subregion, 0x0, sizeof(*subregion));
+ subregion->parent = region;
+}
+
+/*
+ * XXX: replace pgp_ptag_t with something more appropriate for limiting reads
+ */
+
+/**
+ * low-level function to read data from reader function
+ *
+ * Use this function, rather than calling the reader directly.
+ *
+ * If the accumulate flag is set in *stream, the function
+ * adds the read data to the accumulated data, and updates
+ * the accumulated length. This is useful if, for example,
+ * the application wants access to the raw data as well as the
+ * parsed data.
+ *
+ * This function will also try to read the entire amount asked for, but not
+ * if it is over INT_MAX. Obviously many callers will know that they
+ * never ask for that much and so can avoid the extra complexity of
+ * dealing with return codes and filled-in lengths.
+ *
+ * \param *dest
+ * \param *plength
+ * \param flags
+ * \param *stream
+ *
+ * \return PGP_R_OK
+ * \return PGP_R_PARTIAL_READ
+ * \return PGP_R_EOF
+ * \return PGP_R_EARLY_EOF
+ *
+ * \sa #pgp_reader_ret_t for details of return codes
+ */
+
+static int
+sub_base_read(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ size_t n;
+
+ /* reading more than this would look like an error */
+ if (length > INT_MAX)
+ length = INT_MAX;
+
+ for (n = 0; n < length;) {
+ int r;
+
+ r = readinfo->reader(stream, (char *) dest + n, length - n, errors,
+ readinfo, cbinfo);
+ if (r > (int)(length - n)) {
+ (void) fprintf(stderr, "sub_base_read: bad read\n");
+ return 0;
+ }
+ if (r < 0) {
+ return r;
+ }
+ if (r == 0) {
+ break;
+ }
+ n += (unsigned)r;
+ }
+
+ if (n == 0) {
+ return 0;
+ }
+ if (readinfo->accumulate) {
+ if (readinfo->asize < readinfo->alength) {
+ (void) fprintf(stderr, "sub_base_read: bad size\n");
+ return 0;
+ }
+ if (readinfo->alength + n > readinfo->asize) {
+ uint8_t *temp;
+
+ readinfo->asize = (readinfo->asize * 2) + (unsigned)n;
+ temp = realloc(readinfo->accumulated, readinfo->asize);
+ if (temp == NULL) {
+ (void) fprintf(stderr,
+ "sub_base_read: bad alloc\n");
+ return 0;
+ }
+ readinfo->accumulated = temp;
+ }
+ if (readinfo->asize < readinfo->alength + n) {
+ (void) fprintf(stderr, "sub_base_read: bad realloc\n");
+ return 0;
+ }
+ (void) memcpy(readinfo->accumulated + readinfo->alength, dest,
+ n);
+ }
+ /* we track length anyway, because it is used for packet offsets */
+ readinfo->alength += (unsigned)n;
+ /* and also the position */
+ readinfo->position += (unsigned)n;
+
+ return (int)n;
+}
+
+int
+pgp_stacked_read(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ return sub_base_read(stream, dest, length, errors, readinfo->next, cbinfo);
+}
+
+/* This will do a full read so long as length < MAX_INT */
+static int
+base_read(uint8_t *dest, size_t length, pgp_stream_t *stream)
+{
+ return sub_base_read(stream, dest, length, &stream->errors, &stream->readinfo,
+ &stream->cbinfo);
+}
+
+/*
+ * Read a full size_t's worth. If the return is < than length, then
+ * *last_read tells you why - < 0 for an error, == 0 for EOF
+ */
+
+static size_t
+full_read(pgp_stream_t *stream, uint8_t *dest,
+ size_t length,
+ int *last_read,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ size_t t;
+ int r = 0; /* preset in case some loon calls with length
+ * == 0 */
+
+ for (t = 0; t < length;) {
+ r = sub_base_read(stream, dest + t, length - t, errors, readinfo,
+ cbinfo);
+ if (r <= 0) {
+ *last_read = r;
+ return t;
+ }
+ t += (size_t)r;
+ }
+
+ *last_read = r;
+
+ return t;
+}
+
+
+
+/** Read a scalar value of selected length from reader.
+ *
+ * Read an unsigned scalar value from reader in Big Endian representation.
+ *
+ * This function does not know or care about packet boundaries. It
+ * also assumes that an EOF is an error.
+ *
+ * \param *result The scalar value is stored here
+ * \param *reader Our reader
+ * \param length How many bytes to read
+ * \return 1 on success, 0 on failure
+ */
+static unsigned
+_read_scalar(unsigned *result, unsigned length,
+ pgp_stream_t *stream)
+{
+ unsigned t = 0;
+
+ if (length > sizeof(*result)) {
+ (void) fprintf(stderr, "_read_scalar: bad length\n");
+ return 0;
+ }
+
+ while (length--) {
+ uint8_t c;
+ int r;
+
+ r = base_read(&c, 1, stream);
+ if (r != 1)
+ return 0;
+ t = (t << 8) + c;
+ }
+
+ *result = t;
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Read bytes from a region within the packet.
+ *
+ * Read length bytes into the buffer pointed to by *dest.
+ * Make sure we do not read over the packet boundary.
+ * Updates the Packet Tag's pgp_ptag_t::readc.
+ *
+ * If length would make us read over the packet boundary, or if
+ * reading fails, we call the callback with an error.
+ *
+ * Note that if the region is indeterminate, this can return a short
+ * read - check region->last_read for the length. EOF is indicated by
+ * a success return and region->last_read == 0 in this case (for a
+ * region of known length, EOF is an error).
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param dest The destination buffer
+ * \param length How many bytes to read
+ * \param region Pointer to packet region
+ * \param errors Error stack
+ * \param readinfo Reader info
+ * \param cbinfo Callback info
+ * \return 1 on success, 0 on error
+ */
+unsigned
+pgp_limited_read(pgp_stream_t *stream, uint8_t *dest,
+ size_t length,
+ pgp_region_t *region,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ size_t r;
+ int lr;
+
+ if (!region->indeterminate &&
+ region->readc + length > region->length) {
+ PGP_ERROR_1(errors, PGP_E_P_NOT_ENOUGH_DATA, "%s",
+ "Not enough data");
+ return 0;
+ }
+ r = full_read(stream, dest, length, &lr, errors, readinfo, cbinfo);
+ if (lr < 0) {
+ PGP_ERROR_1(errors, PGP_E_R_READ_FAILED, "%s", "Read failed");
+ return 0;
+ }
+ if (!region->indeterminate && r != length) {
+ PGP_ERROR_1(errors, PGP_E_R_READ_FAILED, "%s", "Read failed");
+ return 0;
+ }
+ region->last_read = (unsigned)r;
+ do {
+ region->readc += (unsigned)r;
+ if (region->parent && region->length > region->parent->length) {
+ (void) fprintf(stderr,
+ "ops_limited_read: bad length\n");
+ return 0;
+ }
+ } while ((region = region->parent) != NULL);
+ return 1;
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Call pgp_limited_read on next in stack
+*/
+unsigned
+pgp_stacked_limited_read(pgp_stream_t *stream, uint8_t *dest, unsigned length,
+ pgp_region_t *region,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ return pgp_limited_read(stream, dest, length, region, errors,
+ readinfo->next, cbinfo);
+}
+
+static unsigned
+limread(uint8_t *dest, unsigned length,
+ pgp_region_t *region, pgp_stream_t *info)
+{
+ return pgp_limited_read(info, dest, length, region, &info->errors,
+ &info->readinfo, &info->cbinfo);
+}
+
+static unsigned
+exact_limread(uint8_t *dest, unsigned len,
+ pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ unsigned ret;
+
+ stream->exact_read = 1;
+ ret = limread(dest, len, region, stream);
+ stream->exact_read = 0;
+ return ret;
+}
+
+/** Skip over length bytes of this packet.
+ *
+ * Calls limread() to skip over some data.
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param length How many bytes to skip
+ * \param *region Pointer to packet region
+ * \param *stream How to parse
+ * \return 1 on success, 0 on error (calls the cb with PGP_PARSER_ERROR in limread()).
+ */
+static int
+limskip(unsigned length, pgp_region_t *region, pgp_stream_t *stream)
+{
+ uint8_t buf[NETPGP_BUFSIZ];
+
+ while (length > 0) {
+ unsigned n = length % NETPGP_BUFSIZ;
+
+ if (!limread(buf, n, region, stream)) {
+ return 0;
+ }
+ length -= n;
+ }
+ return 1;
+}
+
+/** Read a scalar.
+ *
+ * Read a big-endian scalar of length bytes, respecting packet
+ * boundaries (by calling limread() to read the raw data).
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param *dest The scalar value is stored here
+ * \param length How many bytes make up this scalar (at most 4)
+ * \param *region Pointer to current packet region
+ * \param *stream How to parse
+ * \param *cb The callback
+ * \return 1 on success, 0 on error (calls the cb with PGP_PARSER_ERROR in limread()).
+ *
+ * \see RFC4880 3.1
+ */
+static int
+limread_scalar(unsigned *dest,
+ unsigned len,
+ pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ uint8_t c[4] = "";
+ unsigned t;
+ unsigned n;
+
+ if (len > 4) {
+ (void) fprintf(stderr, "limread_scalar: bad length\n");
+ return 0;
+ }
+ /*LINTED*/
+ if (/*CONSTCOND*/sizeof(*dest) < 4) {
+ (void) fprintf(stderr, "limread_scalar: bad dest\n");
+ return 0;
+ }
+ if (!limread(c, len, region, stream)) {
+ return 0;
+ }
+ for (t = 0, n = 0; n < len; ++n) {
+ t = (t << 8) + c[n];
+ }
+ *dest = t;
+ return 1;
+}
+
+/** Read a scalar.
+ *
+ * Read a big-endian scalar of length bytes, respecting packet
+ * boundaries (by calling limread() to read the raw data).
+ *
+ * The value read is stored in a size_t, which is a different size
+ * from an unsigned on some platforms.
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param *dest The scalar value is stored here
+ * \param length How many bytes make up this scalar (at most 4)
+ * \param *region Pointer to current packet region
+ * \param *stream How to parse
+ * \param *cb The callback
+ * \return 1 on success, 0 on error (calls the cb with PGP_PARSER_ERROR in limread()).
+ *
+ * \see RFC4880 3.1
+ */
+static int
+limread_size_t(size_t *dest,
+ unsigned length,
+ pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ unsigned tmp;
+
+ /*
+ * Note that because the scalar is at most 4 bytes, we don't care if
+ * size_t is bigger than usigned
+ */
+ if (!limread_scalar(&tmp, length, region, stream))
+ return 0;
+
+ *dest = tmp;
+ return 1;
+}
+
+/** Read a timestamp.
+ *
+ * Timestamps in OpenPGP are unix time, i.e. seconds since The Epoch (1.1.1970). They are stored in an unsigned scalar
+ * of 4 bytes.
+ *
+ * This function reads the timestamp using limread_scalar().
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param *dest The timestamp is stored here
+ * \param *ptag Pointer to current packet's Packet Tag.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return see limread_scalar()
+ *
+ * \see RFC4880 3.5
+ */
+static int
+limited_read_time(time_t *dest, pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ uint8_t c;
+ time_t mytime = 0;
+ int i;
+
+ /*
+ * Cannot assume that time_t is 4 octets long -
+ * SunOS 5.10 and NetBSD both have 64-bit time_ts.
+ */
+ if (/* CONSTCOND */sizeof(time_t) == 4) {
+ return limread_scalar((unsigned *)(void *)dest, 4, region, stream);
+ }
+ for (i = 0; i < 4; i++) {
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ mytime = (mytime << 8) + c;
+ }
+ *dest = mytime;
+ return 1;
+}
+
+/**
+ * \ingroup Core_MPI
+ * Read a multiprecision integer.
+ *
+ * Large numbers (multiprecision integers, MPI) are stored in OpenPGP in two parts. First there is a 2 byte scalar
+ * indicating the length of the following MPI in Bits. Then follow the bits that make up the actual number, most
+ * significant bits first (Big Endian). The most significant bit in the MPI is supposed to be 1 (unless the MPI is
+ * encrypted - then it may be different as the bit count refers to the plain text but the bits are encrypted).
+ *
+ * Unused bits (i.e. those filling up the most significant byte from the left to the first bits that counts) are
+ * supposed to be cleared - I guess. XXX - does anything actually say so?
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param **pgn return the integer there - the BIGNUM is created by BN_bin2bn() and probably needs to be freed
+ * by the caller XXX right ben?
+ * \param *ptag Pointer to current packet's Packet Tag.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error (by limread_scalar() or limread() or if the MPI is not properly formed (XXX
+ * see comment below - the callback is called with a PGP_PARSER_ERROR in case of an error)
+ *
+ * \see RFC4880 3.2
+ */
+static int
+limread_mpi(BIGNUM **pbn, pgp_region_t *region, pgp_stream_t *stream)
+{
+ uint8_t buf[NETPGP_BUFSIZ] = "";
+ /* an MPI has a 2 byte length part.
+ * Length is given in bits, so the
+ * largest we should ever need for
+ * the buffer is NETPGP_BUFSIZ bytes. */
+ unsigned length;
+ unsigned nonzero;
+ unsigned ret;
+
+ stream->reading_mpi_len = 1;
+ ret = (unsigned)limread_scalar(&length, 2, region, stream);
+
+ stream->reading_mpi_len = 0;
+ if (!ret)
+ return 0;
+
+ nonzero = length & 7; /* there should be this many zero bits in the
+ * MS byte */
+ if (!nonzero)
+ nonzero = 8;
+ length = (length + 7) / 8;
+
+ if (length == 0) {
+ /* if we try to read a length of 0, then fail */
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "limread_mpi: 0 length\n");
+ }
+ return 0;
+ }
+ if (length > NETPGP_BUFSIZ) {
+ (void) fprintf(stderr, "limread_mpi: bad length\n");
+ return 0;
+ }
+ if (!limread(buf, length, region, stream)) {
+ return 0;
+ }
+ if (((unsigned)buf[0] >> nonzero) != 0 ||
+ !((unsigned)buf[0] & (1U << (nonzero - 1U)))) {
+ PGP_ERROR_1(&stream->errors, PGP_E_P_MPI_FORMAT_ERROR,
+ "%s", "MPI Format error");
+ /* XXX: Ben, one part of
+ * this constraint does
+ * not apply to
+ * encrypted MPIs the
+ * draft says. -- peter */
+ return 0;
+ }
+ *pbn = BN_bin2bn(buf, (int)length, NULL);
+ return 1;
+}
+
+static unsigned read_new_length(unsigned *, pgp_stream_t *);
+
+/* allocate space, read, and stash data away in a virtual pkt */
+static void
+streamread(pgp_stream_t *stream, unsigned c)
+{
+ int cc;
+
+ stream->virtualpkt = realloc(stream->virtualpkt, stream->virtualc + c);
+ cc = stream->readinfo.reader(stream, &stream->virtualpkt[stream->virtualc],
+ c, &stream->errors, &stream->readinfo, &stream->cbinfo);
+ stream->virtualc += cc;
+}
+
+/* coalesce all the partial blocks together */
+static int
+coalesce_blocks(pgp_stream_t *stream, unsigned length)
+{
+ unsigned c;
+
+ stream->coalescing = 1;
+ /* already read a partial block length - prime the array */
+ streamread(stream, length);
+ while (read_new_length(&c, stream) && stream->partial_read) {
+ /* length we read is partial - add to end of array */
+ streamread(stream, c);
+ }
+ /* not partial - add the last extent to the end of the array */
+ streamread(stream, c);
+ stream->coalescing = 0;
+ return 1;
+}
+
+/** Read some data with a New-Format length from reader.
+ *
+ * \sa Internet-Draft RFC4880.txt Section 4.2.2
+ *
+ * \param *length Where the decoded length will be put
+ * \param *stream How to parse
+ * \return 1 if OK, else 0
+ *
+ */
+
+static unsigned
+read_new_length(unsigned *length, pgp_stream_t *stream)
+{
+ uint8_t c;
+
+ stream->partial_read = 0;
+ if (base_read(&c, 1, stream) != 1) {
+ return 0;
+ }
+ if (c < 192) {
+ /* 1. One-octet packet */
+ *length = c;
+ return 1;
+ }
+ if (c < 224) {
+ /* 2. Two-octet packet */
+ unsigned t = (c - 192) << 8;
+
+ if (base_read(&c, 1, stream) != 1) {
+ return 0;
+ }
+ *length = t + c + 192;
+ return 1;
+ }
+ if (c < 255) {
+ /* 3. Partial Body Length */
+ stream->partial_read = 1;
+ *length = 1 << (c & 0x1f);
+ if (!stream->coalescing) {
+ /* we have been called from coalesce_blocks -
+ * just return with the partial length */
+ coalesce_blocks(stream, *length);
+ *length = stream->virtualc;
+ }
+ return 1;
+ }
+ /* 4. Five-Octet packet */
+ return _read_scalar(length, 4, stream);
+}
+
+/** Read the length information for a new format Packet Tag.
+ *
+ * New style Packet Tags encode the length in one to five octets. This function reads the right amount of bytes and
+ * decodes it to the proper length information.
+ *
+ * This function makes sure to respect packet boundaries.
+ *
+ * \param *length return the length here
+ * \param *ptag Pointer to current packet's Packet Tag.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error (by limread_scalar() or limread() or if the MPI is not properly formed (XXX
+ * see comment below)
+ *
+ * \see RFC4880 4.2.2
+ * \see pgp_ptag_t
+ */
+static int
+limited_read_new_length(unsigned *length, pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ uint8_t c = 0x0;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ if (c < 192) {
+ *length = c;
+ return 1;
+ }
+ if (c < 224) {
+ unsigned t = (c - 192) << 8;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ *length = t + c + 192;
+ return 1;
+ }
+ if (c < 255) {
+ stream->partial_read = 1;
+ *length = 1 << (c & 0x1f);
+ if (!stream->coalescing) {
+ /* we have been called from coalesce_blocks -
+ * just return with the partial length */
+ coalesce_blocks(stream, *length);
+ *length = stream->virtualc;
+ }
+ return 1;
+ }
+ return limread_scalar(length, 4, region, stream);
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+void
+pgp_data_free(pgp_data_t *data)
+{
+ free(data->contents);
+ data->contents = NULL;
+ data->len = 0;
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+static void
+string_free(char **str)
+{
+ free(*str);
+ *str = NULL;
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+/* ! Free packet memory, set pointer to NULL */
+void
+pgp_subpacket_free(pgp_subpacket_t *packet)
+{
+ free(packet->raw);
+ packet->raw = NULL;
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+static void
+headers_free(pgp_headers_t *headers)
+{
+ unsigned n;
+
+ for (n = 0; n < headers->headerc; ++n) {
+ free(headers->headers[n].key);
+ free(headers->headers[n].value);
+ }
+ free(headers->headers);
+ headers->headers = NULL;
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+static void
+cleartext_trailer_free(struct pgp_hash_t **trailer)
+{
+ free(*trailer);
+ *trailer = NULL;
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+static void
+cmd_get_passphrase_free(pgp_seckey_passphrase_t *skp)
+{
+ if (skp->passphrase && *skp->passphrase) {
+ free(*skp->passphrase);
+ *skp->passphrase = NULL;
+ }
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+static void
+free_BN(BIGNUM **pp)
+{
+ BN_free(*pp);
+ *pp = NULL;
+}
+
+/**
+ * \ingroup Core_Create
+ * \brief Free the memory used when parsing a signature
+ * \param sig
+ */
+static void
+sig_free(pgp_sig_t *sig)
+{
+ switch (sig->info.key_alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ free_BN(&sig->info.sig.rsa.sig);
+ break;
+
+ case PGP_PKA_DSA:
+ free_BN(&sig->info.sig.dsa.r);
+ free_BN(&sig->info.sig.dsa.s);
+ break;
+
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ free_BN(&sig->info.sig.elgamal.r);
+ free_BN(&sig->info.sig.elgamal.s);
+ break;
+
+ case PGP_PKA_PRIVATE00:
+ case PGP_PKA_PRIVATE01:
+ case PGP_PKA_PRIVATE02:
+ case PGP_PKA_PRIVATE03:
+ case PGP_PKA_PRIVATE04:
+ case PGP_PKA_PRIVATE05:
+ case PGP_PKA_PRIVATE06:
+ case PGP_PKA_PRIVATE07:
+ case PGP_PKA_PRIVATE08:
+ case PGP_PKA_PRIVATE09:
+ case PGP_PKA_PRIVATE10:
+ pgp_data_free(&sig->info.sig.unknown);
+ break;
+
+ default:
+ (void) fprintf(stderr, "sig_free: bad sig type\n");
+ }
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+/* ! Free any memory allocated when parsing the packet content */
+void
+pgp_parser_content_free(pgp_packet_t *c)
+{
+ switch (c->tag) {
+ case PGP_PARSER_PTAG:
+ case PGP_PTAG_CT_COMPRESSED:
+ case PGP_PTAG_SS_CREATION_TIME:
+ case PGP_PTAG_SS_EXPIRATION_TIME:
+ case PGP_PTAG_SS_KEY_EXPIRY:
+ case PGP_PTAG_SS_TRUST:
+ case PGP_PTAG_SS_ISSUER_KEY_ID:
+ case PGP_PTAG_CT_1_PASS_SIG:
+ case PGP_PTAG_SS_PRIMARY_USER_ID:
+ case PGP_PTAG_SS_REVOCABLE:
+ case PGP_PTAG_SS_REVOCATION_KEY:
+ case PGP_PTAG_CT_LITDATA_HEADER:
+ case PGP_PTAG_CT_LITDATA_BODY:
+ case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
+ case PGP_PTAG_CT_UNARMOURED_TEXT:
+ case PGP_PTAG_CT_ARMOUR_TRAILER:
+ case PGP_PTAG_CT_SIGNATURE_HEADER:
+ case PGP_PTAG_CT_SE_DATA_HEADER:
+ case PGP_PTAG_CT_SE_IP_DATA_HEADER:
+ case PGP_PTAG_CT_SE_IP_DATA_BODY:
+ case PGP_PTAG_CT_MDC:
+ case PGP_GET_SECKEY:
+ break;
+
+ case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
+ headers_free(&c->u.cleartext_head);
+ break;
+
+ case PGP_PTAG_CT_ARMOUR_HEADER:
+ headers_free(&c->u.armour_header.headers);
+ break;
+
+ case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
+ cleartext_trailer_free(&c->u.cleartext_trailer);
+ break;
+
+ case PGP_PTAG_CT_TRUST:
+ pgp_data_free(&c->u.trust);
+ break;
+
+ case PGP_PTAG_CT_SIGNATURE:
+ case PGP_PTAG_CT_SIGNATURE_FOOTER:
+ sig_free(&c->u.sig);
+ break;
+
+ case PGP_PTAG_CT_PUBLIC_KEY:
+ case PGP_PTAG_CT_PUBLIC_SUBKEY:
+ pgp_pubkey_free(&c->u.pubkey);
+ break;
+
+ case PGP_PTAG_CT_USER_ID:
+ pgp_userid_free(&c->u.userid);
+ break;
+
+ case PGP_PTAG_SS_SIGNERS_USER_ID:
+ pgp_userid_free(&c->u.ss_signer);
+ break;
+
+ case PGP_PTAG_CT_USER_ATTR:
+ pgp_data_free(&c->u.userattr);
+ break;
+
+ case PGP_PTAG_SS_PREFERRED_SKA:
+ pgp_data_free(&c->u.ss_skapref);
+ break;
+
+ case PGP_PTAG_SS_PREFERRED_HASH:
+ pgp_data_free(&c->u.ss_hashpref);
+ break;
+
+ case PGP_PTAG_SS_PREF_COMPRESS:
+ pgp_data_free(&c->u.ss_zpref);
+ break;
+
+ case PGP_PTAG_SS_KEY_FLAGS:
+ pgp_data_free(&c->u.ss_key_flags);
+ break;
+
+ case PGP_PTAG_SS_KEYSERV_PREFS:
+ pgp_data_free(&c->u.ss_key_server_prefs);
+ break;
+
+ case PGP_PTAG_SS_FEATURES:
+ pgp_data_free(&c->u.ss_features);
+ break;
+
+ case PGP_PTAG_SS_NOTATION_DATA:
+ pgp_data_free(&c->u.ss_notation.name);
+ pgp_data_free(&c->u.ss_notation.value);
+ break;
+
+ case PGP_PTAG_SS_REGEXP:
+ string_free(&c->u.ss_regexp);
+ break;
+
+ case PGP_PTAG_SS_POLICY_URI:
+ string_free(&c->u.ss_policy);
+ break;
+
+ case PGP_PTAG_SS_PREF_KEYSERV:
+ string_free(&c->u.ss_keyserv);
+ break;
+
+ case PGP_PTAG_SS_USERDEFINED00:
+ case PGP_PTAG_SS_USERDEFINED01:
+ case PGP_PTAG_SS_USERDEFINED02:
+ case PGP_PTAG_SS_USERDEFINED03:
+ case PGP_PTAG_SS_USERDEFINED04:
+ case PGP_PTAG_SS_USERDEFINED05:
+ case PGP_PTAG_SS_USERDEFINED06:
+ case PGP_PTAG_SS_USERDEFINED07:
+ case PGP_PTAG_SS_USERDEFINED08:
+ case PGP_PTAG_SS_USERDEFINED09:
+ case PGP_PTAG_SS_USERDEFINED10:
+ pgp_data_free(&c->u.ss_userdef);
+ break;
+
+ case PGP_PTAG_SS_RESERVED:
+ pgp_data_free(&c->u.ss_unknown);
+ break;
+
+ case PGP_PTAG_SS_REVOCATION_REASON:
+ string_free(&c->u.ss_revocation.reason);
+ break;
+
+ case PGP_PTAG_SS_EMBEDDED_SIGNATURE:
+ pgp_data_free(&c->u.ss_embedded_sig);
+ break;
+
+ case PGP_PARSER_PACKET_END:
+ pgp_subpacket_free(&c->u.packet);
+ break;
+
+ case PGP_PARSER_ERROR:
+ case PGP_PARSER_ERRCODE:
+ break;
+
+ case PGP_PTAG_CT_SECRET_KEY:
+ case PGP_PTAG_CT_ENCRYPTED_SECRET_KEY:
+ pgp_seckey_free(&c->u.seckey);
+ break;
+
+ case PGP_PTAG_CT_PK_SESSION_KEY:
+ case PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
+ pgp_pk_sesskey_free(&c->u.pk_sesskey);
+ break;
+
+ case PGP_GET_PASSPHRASE:
+ cmd_get_passphrase_free(&c->u.skey_passphrase);
+ break;
+
+ default:
+ fprintf(stderr, "Can't free %d (0x%x)\n", c->tag, c->tag);
+ }
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+void
+pgp_pk_sesskey_free(pgp_pk_sesskey_t *sk)
+{
+ switch (sk->alg) {
+ case PGP_PKA_RSA:
+ free_BN(&sk->params.rsa.encrypted_m);
+ break;
+
+ case PGP_PKA_ELGAMAL:
+ free_BN(&sk->params.elgamal.g_to_k);
+ free_BN(&sk->params.elgamal.encrypted_m);
+ break;
+
+ default:
+ (void) fprintf(stderr, "pgp_pk_sesskey_free: bad alg\n");
+ break;
+ }
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+/* ! Free the memory used when parsing a public key */
+void
+pgp_pubkey_free(pgp_pubkey_t *p)
+{
+ switch (p->alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ free_BN(&p->key.rsa.n);
+ free_BN(&p->key.rsa.e);
+ break;
+
+ case PGP_PKA_DSA:
+ free_BN(&p->key.dsa.p);
+ free_BN(&p->key.dsa.q);
+ free_BN(&p->key.dsa.g);
+ free_BN(&p->key.dsa.y);
+ break;
+
+ case PGP_PKA_ELGAMAL:
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ free_BN(&p->key.elgamal.p);
+ free_BN(&p->key.elgamal.g);
+ free_BN(&p->key.elgamal.y);
+ break;
+
+ case PGP_PKA_NOTHING:
+ /* nothing to free */
+ break;
+
+ default:
+ (void) fprintf(stderr, "pgp_pubkey_free: bad alg\n");
+ }
+}
+
+/**
+ \ingroup Core_ReadPackets
+*/
+static int
+parse_pubkey_data(pgp_pubkey_t *key, pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ uint8_t c = 0x0;
+
+ if (region->readc != 0) {
+ /* We should not have read anything so far */
+ (void) fprintf(stderr, "parse_pubkey_data: bad length\n");
+ return 0;
+ }
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ key->version = (pgp_version_t)c;
+ switch (key->version) {
+ case PGP_V2:
+ case PGP_V3:
+ case PGP_V4:
+ break;
+ default:
+ PGP_ERROR_1(&stream->errors, PGP_E_PROTO_BAD_PUBLIC_KEY_VRSN,
+ "Bad public key version (0x%02x)", key->version);
+ return 0;
+ }
+ if (!limited_read_time(&key->birthtime, region, stream)) {
+ return 0;
+ }
+
+ key->days_valid = 0;
+ if ((key->version == 2 || key->version == 3) &&
+ !limread_scalar(&key->days_valid, 2, region, stream)) {
+ return 0;
+ }
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ key->alg = c;
+
+ switch (key->alg) {
+ case PGP_PKA_DSA:
+ if (!limread_mpi(&key->key.dsa.p, region, stream) ||
+ !limread_mpi(&key->key.dsa.q, region, stream) ||
+ !limread_mpi(&key->key.dsa.g, region, stream) ||
+ !limread_mpi(&key->key.dsa.y, region, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (!limread_mpi(&key->key.rsa.n, region, stream) ||
+ !limread_mpi(&key->key.rsa.e, region, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_ELGAMAL:
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ if (!limread_mpi(&key->key.elgamal.p, region, stream) ||
+ !limread_mpi(&key->key.elgamal.g, region, stream) ||
+ !limread_mpi(&key->key.elgamal.y, region, stream)) {
+ return 0;
+ }
+ break;
+
+ default:
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG,
+ "Unsupported Public Key algorithm (%s)",
+ pgp_show_pka(key->alg));
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse a public key packet.
+ *
+ * This function parses an entire v3 (== v2) or v4 public key packet for RSA, ElGamal, and DSA keys.
+ *
+ * Once the key has been parsed successfully, it is passed to the callback.
+ *
+ * \param *ptag Pointer to the current Packet Tag. This function should consume the entire packet.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ *
+ * \see RFC4880 5.5.2
+ */
+static int
+parse_pubkey(pgp_content_enum tag, pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+
+ if (!parse_pubkey_data(&pkt.u.pubkey, region, stream)) {
+ (void) fprintf(stderr, "parse_pubkey: parse_pubkey_data failed\n");
+ return 0;
+ }
+
+ /* XXX: this test should be done for all packets, surely? */
+ if (region->readc != region->length) {
+ PGP_ERROR_1(&stream->errors, PGP_E_R_UNCONSUMED_DATA,
+ "Unconsumed data (%d)", region->length - region->readc);
+ return 0;
+ }
+ CALLBACK(tag, &stream->cbinfo, &pkt);
+
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse one user attribute packet.
+ *
+ * User attribute packets contain one or more attribute subpackets.
+ * For now, handle the whole packet as raw data.
+ */
+
+static int
+parse_userattr(pgp_region_t *region, pgp_stream_t *stream)
+{
+
+ pgp_packet_t pkt;
+
+ /*
+ * xxx- treat as raw data for now. Could break down further into
+ * attribute sub-packets later - rachel
+ */
+ if (region->readc != 0) {
+ /* We should not have read anything so far */
+ (void) fprintf(stderr, "parse_userattr: bad length\n");
+ return 0;
+ }
+ if (!read_data(&pkt.u.userattr, region, stream)) {
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_CT_USER_ATTR, &stream->cbinfo, &pkt);
+ return 1;
+}
+
+/**
+\ingroup Core_Create
+\brief Free allocated memory
+*/
+/* ! Free the memory used when parsing this packet type */
+void
+pgp_userid_free(uint8_t **id)
+{
+ free(*id);
+ *id = NULL;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse a user id.
+ *
+ * This function parses an user id packet, which is basically just a char array the size of the packet.
+ *
+ * The char array is to be treated as an UTF-8 string.
+ *
+ * The userid gets null terminated by this function. Freeing it is the responsibility of the caller.
+ *
+ * Once the userid has been parsed successfully, it is passed to the callback.
+ *
+ * \param *ptag Pointer to the Packet Tag. This function should consume the entire packet.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ *
+ * \see RFC4880 5.11
+ */
+static int
+parse_userid(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+
+ if (region->readc != 0) {
+ /* We should not have read anything so far */
+ (void) fprintf(stderr, "parse_userid: bad length\n");
+ return 0;
+ }
+
+ if ((pkt.u.userid = calloc(1, region->length + 1)) == NULL) {
+ (void) fprintf(stderr, "parse_userid: bad alloc\n");
+ return 0;
+ }
+
+ if (region->length &&
+ !limread(pkt.u.userid, region->length, region,
+ stream)) {
+ return 0;
+ }
+ pkt.u.userid[region->length] = 0x0;
+ CALLBACK(PGP_PTAG_CT_USER_ID, &stream->cbinfo, &pkt);
+ return 1;
+}
+
+static pgp_hash_t *
+parse_hash_find(pgp_stream_t *stream, const uint8_t *keyid)
+{
+ pgp_hashtype_t *hp;
+ size_t n;
+
+ for (n = 0, hp = stream->hashes; n < stream->hashc; n++, hp++) {
+ if (memcmp(hp->keyid, keyid, PGP_KEY_ID_SIZE) == 0) {
+ return &hp->hash;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * \ingroup Core_Parse
+ * \brief Parse a version 3 signature.
+ *
+ * This function parses an version 3 signature packet, handling RSA and DSA signatures.
+ *
+ * Once the signature has been parsed successfully, it is passed to the callback.
+ *
+ * \param *ptag Pointer to the Packet Tag. This function should consume the entire packet.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ *
+ * \see RFC4880 5.2.2
+ */
+static int
+parse_v3_sig(pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ /* clear signature */
+ (void) memset(&pkt.u.sig, 0x0, sizeof(pkt.u.sig));
+
+ pkt.u.sig.info.version = PGP_V3;
+
+ /* hash info length */
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ if (c != 5) {
+ ERRP(&stream->cbinfo, pkt, "bad hash info length");
+ }
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.type = (pgp_sig_type_t)c;
+ /* XXX: check signature type */
+
+ if (!limited_read_time(&pkt.u.sig.info.birthtime, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.birthtime_set = 1;
+
+ if (!limread(pkt.u.sig.info.signer_id, PGP_KEY_ID_SIZE, region,
+ stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.signer_id_set = 1;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.key_alg = (pgp_pubkey_alg_t)c;
+ /* XXX: check algorithm */
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.hash_alg = (pgp_hash_alg_t)c;
+ /* XXX: check algorithm */
+
+ if (!limread(pkt.u.sig.hash2, 2, region, stream)) {
+ return 0;
+ }
+
+ switch (pkt.u.sig.info.key_alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (!limread_mpi(&pkt.u.sig.info.sig.rsa.sig, region, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_DSA:
+ if (!limread_mpi(&pkt.u.sig.info.sig.dsa.r, region, stream) ||
+ !limread_mpi(&pkt.u.sig.info.sig.dsa.s, region, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ if (!limread_mpi(&pkt.u.sig.info.sig.elgamal.r, region,
+ stream) ||
+ !limread_mpi(&pkt.u.sig.info.sig.elgamal.s, region,
+ stream)) {
+ return 0;
+ }
+ break;
+
+ default:
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_SIGNATURE_ALG,
+ "Unsupported signature key algorithm (%s)",
+ pgp_show_pka(pkt.u.sig.info.key_alg));
+ return 0;
+ }
+
+ if (region->readc != region->length) {
+ PGP_ERROR_1(&stream->errors, PGP_E_R_UNCONSUMED_DATA,
+ "Unconsumed data (%d)",
+ region->length - region->readc);
+ return 0;
+ }
+ if (pkt.u.sig.info.signer_id_set) {
+ pkt.u.sig.hash = parse_hash_find(stream,
+ pkt.u.sig.info.signer_id);
+ }
+ CALLBACK(PGP_PTAG_CT_SIGNATURE, &stream->cbinfo, &pkt);
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse one signature sub-packet.
+ *
+ * Version 4 signatures can have an arbitrary amount of (hashed and
+ * unhashed) subpackets. Subpackets are used to hold optional
+ * attributes of subpackets.
+ *
+ * This function parses one such signature subpacket.
+ *
+ * Once the subpacket has been parsed successfully, it is passed to the callback.
+ *
+ * \param *ptag Pointer to the Packet Tag. This function should consume the entire subpacket.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ *
+ * \see RFC4880 5.2.3
+ */
+static int
+parse_one_sig_subpacket(pgp_sig_t *sig,
+ pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ pgp_region_t subregion;
+ pgp_packet_t pkt;
+ uint8_t bools = 0x0;
+ uint8_t c = 0x0;
+ unsigned doread = 1;
+ unsigned t8;
+ unsigned t7;
+
+ pgp_init_subregion(&subregion, region);
+ if (!limited_read_new_length(&subregion.length, region, stream)) {
+ return 0;
+ }
+
+ if (subregion.length > region->length) {
+ ERRP(&stream->cbinfo, pkt, "Subpacket too long");
+ }
+
+ if (!limread(&c, 1, &subregion, stream)) {
+ return 0;
+ }
+
+ t8 = (c & 0x7f) / 8;
+ t7 = 1 << (c & 7);
+
+ pkt.critical = (unsigned)c >> 7;
+ pkt.tag = (pgp_content_enum)(PGP_PTAG_SIG_SUBPKT_BASE + (c & 0x7f));
+
+ /* Application wants it delivered raw */
+ if (stream->ss_raw[t8] & t7) {
+ pkt.u.ss_raw.tag = pkt.tag;
+ pkt.u.ss_raw.length = subregion.length - 1;
+ pkt.u.ss_raw.raw = calloc(1, pkt.u.ss_raw.length);
+ if (pkt.u.ss_raw.raw == NULL) {
+ (void) fprintf(stderr, "parse_one_sig_subpacket: bad alloc\n");
+ return 0;
+ }
+ if (!limread(pkt.u.ss_raw.raw, (unsigned)pkt.u.ss_raw.length,
+ &subregion, stream)) {
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_RAW_SS, &stream->cbinfo, &pkt);
+ return 1;
+ }
+ switch (pkt.tag) {
+ case PGP_PTAG_SS_CREATION_TIME:
+ case PGP_PTAG_SS_EXPIRATION_TIME:
+ case PGP_PTAG_SS_KEY_EXPIRY:
+ if (!limited_read_time(&pkt.u.ss_time, &subregion, stream))
+ return 0;
+ if (pkt.tag == PGP_PTAG_SS_CREATION_TIME) {
+ sig->info.birthtime = pkt.u.ss_time;
+ sig->info.birthtime_set = 1;
+ }
+ if (pkt.tag == PGP_PTAG_SS_EXPIRATION_TIME) {
+ sig->info.duration = pkt.u.ss_time;
+ sig->info.duration_set = 1;
+ }
+ break;
+
+ case PGP_PTAG_SS_TRUST:
+ if (!limread(&pkt.u.ss_trust.level, 1, &subregion, stream) ||
+ !limread(&pkt.u.ss_trust.amount, 1, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_REVOCABLE:
+ if (!limread(&bools, 1, &subregion, stream)) {
+ return 0;
+ }
+ pkt.u.ss_revocable = !!bools;
+ break;
+
+ case PGP_PTAG_SS_ISSUER_KEY_ID:
+ if (!limread(pkt.u.ss_issuer, PGP_KEY_ID_SIZE, &subregion, stream)) {
+ return 0;
+ }
+ (void) memcpy(sig->info.signer_id, pkt.u.ss_issuer, PGP_KEY_ID_SIZE);
+ sig->info.signer_id_set = 1;
+ break;
+
+ case PGP_PTAG_SS_PREFERRED_SKA:
+ if (!read_data(&pkt.u.ss_skapref, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_PREFERRED_HASH:
+ if (!read_data(&pkt.u.ss_hashpref, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_PREF_COMPRESS:
+ if (!read_data(&pkt.u.ss_zpref, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_PRIMARY_USER_ID:
+ if (!limread(&bools, 1, &subregion, stream)) {
+ return 0;
+ }
+ pkt.u.ss_primary_userid = !!bools;
+ break;
+
+ case PGP_PTAG_SS_KEY_FLAGS:
+ if (!read_data(&pkt.u.ss_key_flags, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_KEYSERV_PREFS:
+ if (!read_data(&pkt.u.ss_key_server_prefs, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_FEATURES:
+ if (!read_data(&pkt.u.ss_features, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_SIGNERS_USER_ID:
+ if (!read_unsig_str(&pkt.u.ss_signer, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_EMBEDDED_SIGNATURE:
+ /* \todo should do something with this sig? */
+ if (!read_data(&pkt.u.ss_embedded_sig, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_NOTATION_DATA:
+ if (!limread_data(&pkt.u.ss_notation.flags, 4,
+ &subregion, stream)) {
+ return 0;
+ }
+ if (!limread_size_t(&pkt.u.ss_notation.name.len, 2,
+ &subregion, stream)) {
+ return 0;
+ }
+ if (!limread_size_t(&pkt.u.ss_notation.value.len, 2,
+ &subregion, stream)) {
+ return 0;
+ }
+ if (!limread_data(&pkt.u.ss_notation.name,
+ (unsigned)pkt.u.ss_notation.name.len,
+ &subregion, stream)) {
+ return 0;
+ }
+ if (!limread_data(&pkt.u.ss_notation.value,
+ (unsigned)pkt.u.ss_notation.value.len,
+ &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_POLICY_URI:
+ if (!read_string(&pkt.u.ss_policy, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_REGEXP:
+ if (!read_string(&pkt.u.ss_regexp, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_PREF_KEYSERV:
+ if (!read_string(&pkt.u.ss_keyserv, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_USERDEFINED00:
+ case PGP_PTAG_SS_USERDEFINED01:
+ case PGP_PTAG_SS_USERDEFINED02:
+ case PGP_PTAG_SS_USERDEFINED03:
+ case PGP_PTAG_SS_USERDEFINED04:
+ case PGP_PTAG_SS_USERDEFINED05:
+ case PGP_PTAG_SS_USERDEFINED06:
+ case PGP_PTAG_SS_USERDEFINED07:
+ case PGP_PTAG_SS_USERDEFINED08:
+ case PGP_PTAG_SS_USERDEFINED09:
+ case PGP_PTAG_SS_USERDEFINED10:
+ if (!read_data(&pkt.u.ss_userdef, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_RESERVED:
+ if (!read_data(&pkt.u.ss_unknown, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_REVOCATION_REASON:
+ /* first byte is the machine-readable code */
+ if (!limread(&pkt.u.ss_revocation.code, 1, &subregion, stream)) {
+ return 0;
+ }
+ /* the rest is a human-readable UTF-8 string */
+ if (!read_string(&pkt.u.ss_revocation.reason, &subregion,
+ stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PTAG_SS_REVOCATION_KEY:
+ /* octet 0 = class. Bit 0x80 must be set */
+ if (!limread(&pkt.u.ss_revocation_key.class, 1,
+ &subregion, stream)) {
+ return 0;
+ }
+ if (!(pkt.u.ss_revocation_key.class & 0x80)) {
+ printf("Warning: PGP_PTAG_SS_REVOCATION_KEY class: "
+ "Bit 0x80 should be set\n");
+ return 0;
+ }
+ /* octet 1 = algid */
+ if (!limread(&pkt.u.ss_revocation_key.algid, 1,
+ &subregion, stream)) {
+ return 0;
+ }
+ /* octets 2-21 = fingerprint */
+ if (!limread(&pkt.u.ss_revocation_key.fingerprint[0],
+ PGP_FINGERPRINT_SIZE, &subregion, stream)) {
+ return 0;
+ }
+ break;
+
+ default:
+ if (stream->ss_parsed[t8] & t7) {
+ PGP_ERROR_1(&stream->errors, PGP_E_PROTO_UNKNOWN_SS,
+ "Unknown signature subpacket type (%d)",
+ c & 0x7f);
+ }
+ doread = 0;
+ break;
+ }
+
+ /* Application doesn't want it delivered parsed */
+ if (!(stream->ss_parsed[t8] & t7)) {
+ if (pkt.critical) {
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_PROTO_CRITICAL_SS_IGNORED,
+ "Critical signature subpacket ignored (%d)",
+ c & 0x7f);
+ }
+ if (!doread &&
+ !limskip(subregion.length - 1, &subregion, stream)) {
+ return 0;
+ }
+ if (doread) {
+ pgp_parser_content_free(&pkt);
+ }
+ return 1;
+ }
+ if (doread && subregion.readc != subregion.length) {
+ PGP_ERROR_1(&stream->errors, PGP_E_R_UNCONSUMED_DATA,
+ "Unconsumed data (%d)",
+ subregion.length - subregion.readc);
+ return 0;
+ }
+ CALLBACK(pkt.tag, &stream->cbinfo, &pkt);
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse several signature subpackets.
+ *
+ * Hashed and unhashed subpacket sets are preceded by an octet count that specifies the length of the complete set.
+ * This function parses this length and then calls parse_one_sig_subpacket() for each subpacket until the
+ * entire set is consumed.
+ *
+ * This function does not call the callback directly, parse_one_sig_subpacket() does for each subpacket.
+ *
+ * \param *ptag Pointer to the Packet Tag.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ *
+ * \see RFC4880 5.2.3
+ */
+static int
+parse_sig_subpkts(pgp_sig_t *sig,
+ pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ pgp_region_t subregion;
+ pgp_packet_t pkt;
+
+ pgp_init_subregion(&subregion, region);
+ if (!limread_scalar(&subregion.length, 2, region, stream)) {
+ return 0;
+ }
+
+ if (subregion.length > region->length) {
+ ERRP(&stream->cbinfo, pkt, "Subpacket set too long");
+ }
+
+ while (subregion.readc < subregion.length) {
+ if (!parse_one_sig_subpacket(sig, &subregion, stream)) {
+ return 0;
+ }
+ }
+
+ if (subregion.readc != subregion.length) {
+ if (!limskip(subregion.length - subregion.readc,
+ &subregion, stream)) {
+ ERRP(&stream->cbinfo, pkt,
+"parse_sig_subpkts: subpacket length read mismatch");
+ }
+ ERRP(&stream->cbinfo, pkt, "Subpacket length mismatch");
+ }
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse a version 4 signature.
+ *
+ * This function parses a version 4 signature including all its hashed and unhashed subpackets.
+ *
+ * Once the signature packet has been parsed successfully, it is passed to the callback.
+ *
+ * \param *ptag Pointer to the Packet Tag.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ *
+ * \see RFC4880 5.2.3
+ */
+static int
+parse_v4_sig(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "\nparse_v4_sig\n");
+ }
+ /* clear signature */
+ (void) memset(&pkt.u.sig, 0x0, sizeof(pkt.u.sig));
+
+ /*
+ * We need to hash the packet data from version through the hashed
+ * subpacket data
+ */
+
+ pkt.u.sig.v4_hashstart = stream->readinfo.alength - 1;
+
+ /* Set version,type,algorithms */
+
+ pkt.u.sig.info.version = PGP_V4;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.type = (pgp_sig_type_t)c;
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "signature type=%d (%s)\n",
+ pkt.u.sig.info.type,
+ pgp_show_sig_type(pkt.u.sig.info.type));
+ }
+ /* XXX: check signature type */
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.key_alg = (pgp_pubkey_alg_t)c;
+ /* XXX: check key algorithm */
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "key_alg=%d (%s)\n",
+ pkt.u.sig.info.key_alg,
+ pgp_show_pka(pkt.u.sig.info.key_alg));
+ }
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.sig.info.hash_alg = (pgp_hash_alg_t)c;
+ /* XXX: check hash algorithm */
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "hash_alg=%d %s\n",
+ pkt.u.sig.info.hash_alg,
+ pgp_show_hash_alg(pkt.u.sig.info.hash_alg));
+ }
+ CALLBACK(PGP_PTAG_CT_SIGNATURE_HEADER, &stream->cbinfo, &pkt);
+
+ if (!parse_sig_subpkts(&pkt.u.sig, region, stream)) {
+ return 0;
+ }
+
+ pkt.u.sig.info.v4_hashlen = stream->readinfo.alength
+ - pkt.u.sig.v4_hashstart;
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "v4_hashlen=%zd\n", pkt.u.sig.info.v4_hashlen);
+ }
+
+ /* copy hashed subpackets */
+ if (pkt.u.sig.info.v4_hashed) {
+ free(pkt.u.sig.info.v4_hashed);
+ }
+ pkt.u.sig.info.v4_hashed = calloc(1, pkt.u.sig.info.v4_hashlen);
+ if (pkt.u.sig.info.v4_hashed == NULL) {
+ (void) fprintf(stderr, "parse_v4_sig: bad alloc\n");
+ return 0;
+ }
+
+ if (!stream->readinfo.accumulate) {
+ /* We must accumulate, else we can't check the signature */
+ fprintf(stderr, "*** ERROR: must set accumulate to 1\n");
+ return 0;
+ }
+ (void) memcpy(pkt.u.sig.info.v4_hashed,
+ stream->readinfo.accumulated + pkt.u.sig.v4_hashstart,
+ pkt.u.sig.info.v4_hashlen);
+
+ if (!parse_sig_subpkts(&pkt.u.sig, region, stream)) {
+ return 0;
+ }
+
+ if (!limread(pkt.u.sig.hash2, 2, region, stream)) {
+ return 0;
+ }
+
+ switch (pkt.u.sig.info.key_alg) {
+ case PGP_PKA_RSA:
+ if (!limread_mpi(&pkt.u.sig.info.sig.rsa.sig, region, stream)) {
+ return 0;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "parse_v4_sig: RSA: sig is\n");
+ BN_print_fp(stderr, pkt.u.sig.info.sig.rsa.sig);
+ (void) fprintf(stderr, "\n");
+ }
+ break;
+
+ case PGP_PKA_DSA:
+ if (!limread_mpi(&pkt.u.sig.info.sig.dsa.r, region, stream)) {
+ /*
+ * usually if this fails, it just means we've reached
+ * the end of the keyring
+ */
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr,
+ "Error reading DSA r field in signature");
+ }
+ return 0;
+ }
+ if (!limread_mpi(&pkt.u.sig.info.sig.dsa.s, region, stream)) {
+ ERRP(&stream->cbinfo, pkt,
+ "Error reading DSA s field in signature");
+ }
+ break;
+
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ if (!limread_mpi(&pkt.u.sig.info.sig.elgamal.r, region,
+ stream) ||
+ !limread_mpi(&pkt.u.sig.info.sig.elgamal.s, region,
+ stream)) {
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_PRIVATE00:
+ case PGP_PKA_PRIVATE01:
+ case PGP_PKA_PRIVATE02:
+ case PGP_PKA_PRIVATE03:
+ case PGP_PKA_PRIVATE04:
+ case PGP_PKA_PRIVATE05:
+ case PGP_PKA_PRIVATE06:
+ case PGP_PKA_PRIVATE07:
+ case PGP_PKA_PRIVATE08:
+ case PGP_PKA_PRIVATE09:
+ case PGP_PKA_PRIVATE10:
+ if (!read_data(&pkt.u.sig.info.sig.unknown, region, stream)) {
+ return 0;
+ }
+ break;
+
+ default:
+ PGP_ERROR_1(&stream->errors, PGP_E_ALG_UNSUPPORTED_SIGNATURE_ALG,
+ "Bad v4 signature key algorithm (%s)",
+ pgp_show_pka(pkt.u.sig.info.key_alg));
+ return 0;
+ }
+ if (region->readc != region->length) {
+ PGP_ERROR_1(&stream->errors, PGP_E_R_UNCONSUMED_DATA,
+ "Unconsumed data (%d)",
+ region->length - region->readc);
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_CT_SIGNATURE_FOOTER, &stream->cbinfo, &pkt);
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse a signature subpacket.
+ *
+ * This function calls the appropriate function to handle v3 or v4 signatures.
+ *
+ * Once the signature packet has been parsed successfully, it is passed to the callback.
+ *
+ * \param *ptag Pointer to the Packet Tag.
+ * \param *reader Our reader
+ * \param *cb The callback
+ * \return 1 on success, 0 on error
+ */
+static int
+parse_sig(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ if (region->readc != 0) {
+ /* We should not have read anything so far */
+ (void) fprintf(stderr, "parse_sig: bad length\n");
+ return 0;
+ }
+
+ (void) memset(&pkt, 0x0, sizeof(pkt));
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ if (c == 2 || c == 3) {
+ return parse_v3_sig(region, stream);
+ }
+ if (c == 4) {
+ return parse_v4_sig(region, stream);
+ }
+ PGP_ERROR_1(&stream->errors, PGP_E_PROTO_BAD_SIGNATURE_VRSN,
+ "Bad signature version (%d)", c);
+ return 0;
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Parse Compressed packet
+*/
+static int
+parse_compressed(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+
+ pkt.u.compressed = (pgp_compression_type_t)c;
+
+ CALLBACK(PGP_PTAG_CT_COMPRESSED, &stream->cbinfo, &pkt);
+
+ /*
+ * The content of a compressed data packet is more OpenPGP packets
+ * once decompressed, so recursively handle them
+ */
+
+ return pgp_decompress(region, stream, pkt.u.compressed);
+}
+
+/* XXX: this could be improved by sharing all hashes that are the */
+/* same, then duping them just before checking the signature. */
+static void
+parse_hash_init(pgp_stream_t *stream, pgp_hash_alg_t type,
+ const uint8_t *keyid)
+{
+ pgp_hashtype_t *hash;
+
+ hash = realloc(stream->hashes,
+ (stream->hashc + 1) * sizeof(*stream->hashes));
+ if (hash == NULL) {
+ (void) fprintf(stderr, "parse_hash_init: bad alloc 0\n");
+ /* just continue and die here */
+ /* XXX - agc - no way to return failure */
+ } else {
+ stream->hashes = hash;
+ }
+ hash = &stream->hashes[stream->hashc++];
+
+ pgp_hash_any(&hash->hash, type);
+ if (!hash->hash.init(&hash->hash)) {
+ (void) fprintf(stderr, "parse_hash_init: bad alloc\n");
+ /* just continue and die here */
+ /* XXX - agc - no way to return failure */
+ }
+ (void) memcpy(hash->keyid, keyid, sizeof(hash->keyid));
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Parse a One Pass Signature packet
+*/
+static int
+parse_one_pass(pgp_region_t * region, pgp_stream_t * stream)
+{
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ if (!limread(&pkt.u.one_pass_sig.version, 1, region, stream)) {
+ return 0;
+ }
+ if (pkt.u.one_pass_sig.version != 3) {
+ PGP_ERROR_1(&stream->errors, PGP_E_PROTO_BAD_ONE_PASS_SIG_VRSN,
+ "Bad one-pass signature version (%d)",
+ pkt.u.one_pass_sig.version);
+ return 0;
+ }
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.one_pass_sig.sig_type = (pgp_sig_type_t)c;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.one_pass_sig.hash_alg = (pgp_hash_alg_t)c;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.one_pass_sig.key_alg = (pgp_pubkey_alg_t)c;
+
+ if (!limread(pkt.u.one_pass_sig.keyid,
+ (unsigned)sizeof(pkt.u.one_pass_sig.keyid),
+ region, stream)) {
+ return 0;
+ }
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.one_pass_sig.nested = !!c;
+ CALLBACK(PGP_PTAG_CT_1_PASS_SIG, &stream->cbinfo, &pkt);
+ /* XXX: we should, perhaps, let the app choose whether to hash or not */
+ parse_hash_init(stream, pkt.u.one_pass_sig.hash_alg,
+ pkt.u.one_pass_sig.keyid);
+ return 1;
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Parse a Trust packet
+*/
+static int
+parse_trust(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+
+ if (!read_data(&pkt.u.trust, region, stream)) {
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_CT_TRUST, &stream->cbinfo, &pkt);
+ return 1;
+}
+
+static void
+parse_hash_data(pgp_stream_t *stream, const void *data,
+ size_t length)
+{
+ size_t n;
+
+ for (n = 0; n < stream->hashc; ++n) {
+ stream->hashes[n].hash.add(&stream->hashes[n].hash, data, (unsigned)length);
+ }
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Parse a Literal Data packet
+*/
+static int
+parse_litdata(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_memory_t *mem;
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.litdata_header.format = (pgp_litdata_enum)c;
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ if (!limread((uint8_t *)pkt.u.litdata_header.filename,
+ (unsigned)c, region, stream)) {
+ return 0;
+ }
+ pkt.u.litdata_header.filename[c] = '\0';
+ if (!limited_read_time(&pkt.u.litdata_header.mtime, region, stream)) {
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_CT_LITDATA_HEADER, &stream->cbinfo, &pkt);
+ mem = pkt.u.litdata_body.mem = pgp_memory_new();
+ pgp_memory_init(pkt.u.litdata_body.mem,
+ (unsigned)((region->length * 101) / 100) + 12);
+ pkt.u.litdata_body.data = mem->buf;
+
+ while (region->readc < region->length) {
+ unsigned readc = region->length - region->readc;
+
+ if (!limread(mem->buf, readc, region, stream)) {
+ return 0;
+ }
+ pkt.u.litdata_body.length = readc;
+ parse_hash_data(stream, pkt.u.litdata_body.data, region->length);
+ CALLBACK(PGP_PTAG_CT_LITDATA_BODY, &stream->cbinfo, &pkt);
+ }
+
+ /* XXX - get rid of mem here? */
+
+ return 1;
+}
+
+/**
+ * \ingroup Core_Create
+ *
+ * pgp_seckey_free() frees the memory associated with "key". Note that
+ * the key itself is not freed.
+ *
+ * \param key
+ */
+
+void
+pgp_seckey_free(pgp_seckey_t *key)
+{
+ switch (key->pubkey.alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ free_BN(&key->key.rsa.d);
+ free_BN(&key->key.rsa.p);
+ free_BN(&key->key.rsa.q);
+ free_BN(&key->key.rsa.u);
+ break;
+
+ case PGP_PKA_DSA:
+ free_BN(&key->key.dsa.x);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_seckey_free: Unknown algorithm: %d (%s)\n",
+ key->pubkey.alg,
+ pgp_show_pka(key->pubkey.alg));
+ }
+ free(key->checkhash);
+}
+
+static int
+consume_packet(pgp_region_t *region, pgp_stream_t *stream, unsigned warn)
+{
+ pgp_packet_t pkt;
+ pgp_data_t remainder;
+
+ if (region->indeterminate) {
+ ERRP(&stream->cbinfo, pkt,
+ "Can't consume indeterminate packets");
+ }
+
+ if (read_data(&remainder, region, stream)) {
+ /* now throw it away */
+ pgp_data_free(&remainder);
+ if (warn) {
+ PGP_ERROR_1(&stream->errors, PGP_E_P_PACKET_CONSUMED,
+ "%s", "Warning: packet consumer");
+ }
+ return 1;
+ }
+ PGP_ERROR_1(&stream->errors, PGP_E_P_PACKET_NOT_CONSUMED,
+ "%s", (warn) ? "Warning: Packet was not consumed" :
+ "Packet was not consumed");
+ return warn;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse a secret key
+ */
+static int
+parse_seckey(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+ pgp_region_t encregion;
+ pgp_region_t *saved_region = NULL;
+ pgp_crypt_t decrypt;
+ pgp_hash_t checkhash;
+ unsigned blocksize;
+ unsigned crypted;
+ uint8_t c = 0x0;
+ int ret = 1;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "\n---------\nparse_seckey:\n");
+ fprintf(stderr,
+ "region length=%u, readc=%u, remainder=%u\n",
+ region->length, region->readc,
+ region->length - region->readc);
+ }
+ (void) memset(&pkt, 0x0, sizeof(pkt));
+ if (!parse_pubkey_data(&pkt.u.seckey.pubkey, region, stream)) {
+ return 0;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "parse_seckey: public key parsed\n");
+ pgp_print_pubkey(&pkt.u.seckey.pubkey);
+ }
+ stream->reading_v3_secret = (pkt.u.seckey.pubkey.version != PGP_V4);
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.seckey.s2k_usage = (pgp_s2k_usage_t)c;
+
+ if (pkt.u.seckey.s2k_usage == PGP_S2KU_ENCRYPTED ||
+ pkt.u.seckey.s2k_usage == PGP_S2KU_ENCRYPTED_AND_HASHED) {
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.seckey.alg = (pgp_symm_alg_t)c;
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.seckey.s2k_specifier = (pgp_s2k_specifier_t)c;
+ switch (pkt.u.seckey.s2k_specifier) {
+ case PGP_S2KS_SIMPLE:
+ case PGP_S2KS_SALTED:
+ case PGP_S2KS_ITERATED_AND_SALTED:
+ break;
+ default:
+ (void) fprintf(stderr,
+ "parse_seckey: bad seckey\n");
+ return 0;
+ }
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.seckey.hash_alg = (pgp_hash_alg_t)c;
+ if (pkt.u.seckey.s2k_specifier != PGP_S2KS_SIMPLE &&
+ !limread(pkt.u.seckey.salt, 8, region, stream)) {
+ return 0;
+ }
+ if (pkt.u.seckey.s2k_specifier ==
+ PGP_S2KS_ITERATED_AND_SALTED) {
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.seckey.octetc =
+ (16 + ((unsigned)c & 15)) <<
+ (((unsigned)c >> 4) + 6);
+ }
+ } else if (pkt.u.seckey.s2k_usage != PGP_S2KU_NONE) {
+ /* this is V3 style, looks just like a V4 simple hash */
+ pkt.u.seckey.alg = (pgp_symm_alg_t)c;
+ pkt.u.seckey.s2k_usage = PGP_S2KU_ENCRYPTED;
+ pkt.u.seckey.s2k_specifier = PGP_S2KS_SIMPLE;
+ pkt.u.seckey.hash_alg = PGP_HASH_MD5;
+ }
+ crypted = pkt.u.seckey.s2k_usage == PGP_S2KU_ENCRYPTED ||
+ pkt.u.seckey.s2k_usage == PGP_S2KU_ENCRYPTED_AND_HASHED;
+
+ if (crypted) {
+ pgp_packet_t seckey;
+ pgp_hash_t hashes[(PGP_MAX_KEY_SIZE + PGP_MIN_HASH_SIZE - 1) / PGP_MIN_HASH_SIZE];
+ unsigned passlen;
+ uint8_t key[PGP_MAX_KEY_SIZE + PGP_MAX_HASH_SIZE];
+ char *passphrase;
+ int hashsize;
+ int keysize;
+ int n;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "crypted seckey\n");
+ }
+ blocksize = pgp_block_size(pkt.u.seckey.alg);
+ if (blocksize == 0 || blocksize > PGP_MAX_BLOCK_SIZE) {
+ (void) fprintf(stderr,
+ "parse_seckey: bad blocksize\n");
+ return 0;
+ }
+
+ if (!limread(pkt.u.seckey.iv, blocksize, region, stream)) {
+ return 0;
+ }
+ (void) memset(&seckey, 0x0, sizeof(seckey));
+ passphrase = NULL;
+ seckey.u.skey_passphrase.passphrase = &passphrase;
+ seckey.u.skey_passphrase.seckey = &pkt.u.seckey;
+ CALLBACK(PGP_GET_PASSPHRASE, &stream->cbinfo, &seckey);
+ if (!passphrase) {
+ if (pgp_get_debug_level(__FILE__)) {
+ /* \todo make into proper error */
+ (void) fprintf(stderr,
+ "parse_seckey: can't get passphrase\n");
+ }
+ if (!consume_packet(region, stream, 0)) {
+ return 0;
+ }
+
+ CALLBACK(PGP_PTAG_CT_ENCRYPTED_SECRET_KEY,
+ &stream->cbinfo, &pkt);
+
+ return 1;
+ }
+ keysize = pgp_key_size(pkt.u.seckey.alg);
+ if (keysize == 0 || keysize > PGP_MAX_KEY_SIZE) {
+ (void) fprintf(stderr,
+ "parse_seckey: bad keysize\n");
+ return 0;
+ }
+
+ /* Hardcoded SHA1 for just now */
+ pkt.u.seckey.hash_alg = PGP_HASH_SHA1;
+ hashsize = pgp_hash_size(pkt.u.seckey.hash_alg);
+ if (hashsize == 0 || hashsize > PGP_MAX_HASH_SIZE) {
+ (void) fprintf(stderr,
+ "parse_seckey: bad hashsize\n");
+ return 0;
+ }
+
+ for (n = 0; n * hashsize < keysize; ++n) {
+ int i;
+
+ pgp_hash_any(&hashes[n],
+ pkt.u.seckey.hash_alg);
+ if (!hashes[n].init(&hashes[n])) {
+ (void) fprintf(stderr,
+ "parse_seckey: bad alloc\n");
+ return 0;
+ }
+ /* preload hashes with zeroes... */
+ for (i = 0; i < n; ++i) {
+ hashes[n].add(&hashes[n],
+ (const uint8_t *) "", 1);
+ }
+ }
+ passlen = (unsigned)strlen(passphrase);
+ for (n = 0; n * hashsize < keysize; ++n) {
+ unsigned i;
+
+ switch (pkt.u.seckey.s2k_specifier) {
+ case PGP_S2KS_SALTED:
+ hashes[n].add(&hashes[n],
+ pkt.u.seckey.salt,
+ PGP_SALT_SIZE);
+ /* FALLTHROUGH */
+ case PGP_S2KS_SIMPLE:
+ hashes[n].add(&hashes[n],
+ (uint8_t *)passphrase, (unsigned)passlen);
+ break;
+
+ case PGP_S2KS_ITERATED_AND_SALTED:
+ for (i = 0; i < pkt.u.seckey.octetc;
+ i += passlen + PGP_SALT_SIZE) {
+ unsigned j;
+
+ j = passlen + PGP_SALT_SIZE;
+ if (i + j > pkt.u.seckey.octetc && i != 0) {
+ j = pkt.u.seckey.octetc - i;
+ }
+ hashes[n].add(&hashes[n],
+ pkt.u.seckey.salt,
+ (unsigned)(j > PGP_SALT_SIZE) ?
+ PGP_SALT_SIZE : j);
+ if (j > PGP_SALT_SIZE) {
+ hashes[n].add(&hashes[n],
+ (uint8_t *) passphrase,
+ j - PGP_SALT_SIZE);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (n = 0; n * hashsize < keysize; ++n) {
+ int r;
+
+ r = hashes[n].finish(&hashes[n], key + n * hashsize);
+ if (r != hashsize) {
+ (void) fprintf(stderr,
+ "parse_seckey: bad r\n");
+ return 0;
+ }
+ }
+
+ pgp_forget(passphrase, passlen);
+
+ pgp_crypt_any(&decrypt, pkt.u.seckey.alg);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "input iv", pkt.u.seckey.iv, pgp_block_size(pkt.u.seckey.alg));
+ hexdump(stderr, "key", key, CAST_KEY_LENGTH);
+ }
+ decrypt.set_iv(&decrypt, pkt.u.seckey.iv);
+ decrypt.set_crypt_key(&decrypt, key);
+
+ /* now read encrypted data */
+
+ pgp_reader_push_decrypt(stream, &decrypt, region);
+
+ /*
+ * Since all known encryption for PGP doesn't compress, we
+ * can limit to the same length as the current region (for
+ * now).
+ */
+ pgp_init_subregion(&encregion, NULL);
+ encregion.length = region->length - region->readc;
+ if (pkt.u.seckey.pubkey.version != PGP_V4) {
+ encregion.length -= 2;
+ }
+ saved_region = region;
+ region = &encregion;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "parse_seckey: end of crypted passphrase\n");
+ }
+ if (pkt.u.seckey.s2k_usage == PGP_S2KU_ENCRYPTED_AND_HASHED) {
+ /* XXX - Hard-coded SHA1 here ?? Check */
+ pkt.u.seckey.checkhash = calloc(1, PGP_SHA1_HASH_SIZE);
+ if (pkt.u.seckey.checkhash == NULL) {
+ (void) fprintf(stderr, "parse_seckey: bad alloc\n");
+ return 0;
+ }
+ pgp_hash_sha1(&checkhash);
+ pgp_reader_push_hash(stream, &checkhash);
+ } else {
+ pgp_reader_push_sum16(stream);
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "parse_seckey: checkhash, reading MPIs\n");
+ }
+ switch (pkt.u.seckey.pubkey.alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (!limread_mpi(&pkt.u.seckey.key.rsa.d, region, stream) ||
+ !limread_mpi(&pkt.u.seckey.key.rsa.p, region, stream) ||
+ !limread_mpi(&pkt.u.seckey.key.rsa.q, region, stream) ||
+ !limread_mpi(&pkt.u.seckey.key.rsa.u, region, stream)) {
+ ret = 0;
+ }
+ break;
+
+ case PGP_PKA_DSA:
+ if (!limread_mpi(&pkt.u.seckey.key.dsa.x, region, stream)) {
+ ret = 0;
+ }
+ break;
+
+ case PGP_PKA_ELGAMAL:
+ if (!limread_mpi(&pkt.u.seckey.key.elgamal.x, region, stream)) {
+ ret = 0;
+ }
+ break;
+
+ default:
+ PGP_ERROR_2(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG,
+ "Unsupported Public Key algorithm %d (%s)",
+ pkt.u.seckey.pubkey.alg,
+ pgp_show_pka(pkt.u.seckey.pubkey.alg));
+ ret = 0;
+ }
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "4 MPIs read\n");
+ }
+ stream->reading_v3_secret = 0;
+
+ if (pkt.u.seckey.s2k_usage == PGP_S2KU_ENCRYPTED_AND_HASHED) {
+ uint8_t hash[PGP_CHECKHASH_SIZE];
+
+ pgp_reader_pop_hash(stream);
+ checkhash.finish(&checkhash, hash);
+
+ if (crypted &&
+ pkt.u.seckey.pubkey.version != PGP_V4) {
+ pgp_reader_pop_decrypt(stream);
+ region = saved_region;
+ }
+ if (ret) {
+ if (!limread(pkt.u.seckey.checkhash,
+ PGP_CHECKHASH_SIZE, region, stream)) {
+ return 0;
+ }
+
+ if (memcmp(hash, pkt.u.seckey.checkhash,
+ PGP_CHECKHASH_SIZE) != 0) {
+ ERRP(&stream->cbinfo, pkt,
+ "Hash mismatch in secret key");
+ }
+ }
+ } else {
+ uint16_t sum;
+
+ sum = pgp_reader_pop_sum16(stream);
+ if (crypted &&
+ pkt.u.seckey.pubkey.version != PGP_V4) {
+ pgp_reader_pop_decrypt(stream);
+ region = saved_region;
+ }
+ if (ret) {
+ if (!limread_scalar(&pkt.u.seckey.checksum, 2,
+ region, stream))
+ return 0;
+
+ if (sum != pkt.u.seckey.checksum) {
+ ERRP(&stream->cbinfo, pkt,
+ "Checksum mismatch in secret key");
+ }
+ }
+ }
+
+ if (crypted && pkt.u.seckey.pubkey.version == PGP_V4) {
+ pgp_reader_pop_decrypt(stream);
+ }
+ if (region == NULL) {
+ (void) fprintf(stderr, "parse_seckey: NULL region\n");
+ return 0;
+ }
+ if (ret && region->readc != region->length) {
+ (void) fprintf(stderr, "parse_seckey: bad length\n");
+ return 0;
+ }
+ if (!ret) {
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_CT_SECRET_KEY, &stream->cbinfo, &pkt);
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "--- end of parse_seckey\n\n");
+ }
+ return 1;
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Parse a Public Key Session Key packet
+*/
+static int
+parse_pk_sesskey(pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ const pgp_seckey_t *secret;
+ pgp_packet_t sesskey;
+ pgp_packet_t pkt;
+ uint8_t *iv;
+ uint8_t c = 0x0;
+ uint8_t cs[2];
+ unsigned k;
+ BIGNUM *g_to_k;
+ BIGNUM *enc_m;
+ int n;
+ uint8_t unencoded_m_buf[1024];
+
+ if (!limread(&c, 1, region, stream)) {
+ (void) fprintf(stderr, "parse_pk_sesskey - can't read char in region\n");
+ return 0;
+ }
+ pkt.u.pk_sesskey.version = c;
+ if (pkt.u.pk_sesskey.version != 3) {
+ PGP_ERROR_1(&stream->errors, PGP_E_PROTO_BAD_PKSK_VRSN,
+ "Bad public-key encrypted session key version (%d)",
+ pkt.u.pk_sesskey.version);
+ return 0;
+ }
+ if (!limread(pkt.u.pk_sesskey.key_id,
+ (unsigned)sizeof(pkt.u.pk_sesskey.key_id), region, stream)) {
+ return 0;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sesskey: pubkey id", pkt.u.pk_sesskey.key_id, sizeof(pkt.u.pk_sesskey.key_id));
+ }
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.pk_sesskey.alg = (pgp_pubkey_alg_t)c;
+ switch (pkt.u.pk_sesskey.alg) {
+ case PGP_PKA_RSA:
+ if (!limread_mpi(&pkt.u.pk_sesskey.params.rsa.encrypted_m,
+ region, stream)) {
+ return 0;
+ }
+ enc_m = pkt.u.pk_sesskey.params.rsa.encrypted_m;
+ g_to_k = NULL;
+ break;
+
+ case PGP_PKA_DSA:
+ case PGP_PKA_ELGAMAL:
+ if (!limread_mpi(&pkt.u.pk_sesskey.params.elgamal.g_to_k,
+ region, stream) ||
+ !limread_mpi(
+ &pkt.u.pk_sesskey.params.elgamal.encrypted_m,
+ region, stream)) {
+ return 0;
+ }
+ g_to_k = pkt.u.pk_sesskey.params.elgamal.g_to_k;
+ enc_m = pkt.u.pk_sesskey.params.elgamal.encrypted_m;
+ break;
+
+ default:
+ PGP_ERROR_1(&stream->errors,
+ PGP_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG,
+ "Unknown public key algorithm in session key (%s)",
+ pgp_show_pka(pkt.u.pk_sesskey.alg));
+ return 0;
+ }
+
+ (void) memset(&sesskey, 0x0, sizeof(sesskey));
+ secret = NULL;
+ sesskey.u.get_seckey.seckey = &secret;
+ sesskey.u.get_seckey.pk_sesskey = &pkt.u.pk_sesskey;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "getting secret key via callback\n");
+ }
+
+ CALLBACK(PGP_GET_SECKEY, &stream->cbinfo, &sesskey);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "got secret key via callback\n");
+ }
+ if (!secret) {
+ CALLBACK(PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY, &stream->cbinfo,
+ &pkt);
+ return 1;
+ }
+ n = pgp_decrypt_decode_mpi(unencoded_m_buf,
+ (unsigned)sizeof(unencoded_m_buf), g_to_k, enc_m, secret);
+
+ if (n < 1) {
+ ERRP(&stream->cbinfo, pkt, "decrypted message too short");
+ return 0;
+ }
+
+ /* PKA */
+ pkt.u.pk_sesskey.symm_alg = (pgp_symm_alg_t)unencoded_m_buf[0];
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "symm alg %d\n", pkt.u.pk_sesskey.symm_alg);
+ }
+
+ if (!pgp_is_sa_supported(pkt.u.pk_sesskey.symm_alg)) {
+ /* ERR1P */
+ PGP_ERROR_1(&stream->errors, PGP_E_ALG_UNSUPPORTED_SYMMETRIC_ALG,
+ "Symmetric algorithm %s not supported",
+ pgp_show_symm_alg(
+ pkt.u.pk_sesskey.symm_alg));
+ return 0;
+ }
+ k = pgp_key_size(pkt.u.pk_sesskey.symm_alg);
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "key size %d\n", k);
+ }
+
+ if ((unsigned) n != k + 3) {
+ PGP_ERROR_2(&stream->errors, PGP_E_PROTO_DECRYPTED_MSG_WRONG_LEN,
+ "decrypted message wrong length (got %d expected %d)",
+ n, k + 3);
+ return 0;
+ }
+ if (k > sizeof(pkt.u.pk_sesskey.key)) {
+ (void) fprintf(stderr, "parse_pk_sesskey: bad keylength\n");
+ return 0;
+ }
+
+ (void) memcpy(pkt.u.pk_sesskey.key, unencoded_m_buf + 1, k);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "recovered sesskey", pkt.u.pk_sesskey.key, k);
+ }
+ pkt.u.pk_sesskey.checksum = unencoded_m_buf[k + 1] +
+ (unencoded_m_buf[k + 2] << 8);
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "session key checksum: %2x %2x\n",
+ unencoded_m_buf[k + 1], unencoded_m_buf[k + 2]);
+ }
+
+ /* Check checksum */
+ pgp_calc_sesskey_checksum(&pkt.u.pk_sesskey, &cs[0]);
+ if (unencoded_m_buf[k + 1] != cs[0] ||
+ unencoded_m_buf[k + 2] != cs[1]) {
+ PGP_ERROR_4(&stream->errors, PGP_E_PROTO_BAD_SK_CHECKSUM,
+ "Session key checksum wrong: expected %2x %2x, got %2x %2x",
+ cs[0], cs[1], unencoded_m_buf[k + 1],
+ unencoded_m_buf[k + 2]);
+ return 0;
+ }
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "getting pk session key via callback\n");
+ }
+ /* all is well */
+ CALLBACK(PGP_PTAG_CT_PK_SESSION_KEY, &stream->cbinfo, &pkt);
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "got pk session key via callback\n");
+ }
+
+ pgp_crypt_any(&stream->decrypt, pkt.u.pk_sesskey.symm_alg);
+ iv = calloc(1, stream->decrypt.blocksize);
+ if (iv == NULL) {
+ (void) fprintf(stderr, "parse_pk_sesskey: bad alloc\n");
+ return 0;
+ }
+ stream->decrypt.set_iv(&stream->decrypt, iv);
+ stream->decrypt.set_crypt_key(&stream->decrypt, pkt.u.pk_sesskey.key);
+ pgp_encrypt_init(&stream->decrypt);
+ free(iv);
+ return 1;
+}
+
+static int
+decrypt_se_data(pgp_content_enum tag, pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ pgp_crypt_t *decrypt;
+ const int printerrors = 1;
+ int r = 1;
+
+ decrypt = pgp_get_decrypt(stream);
+ if (decrypt) {
+ pgp_region_t encregion;
+ unsigned b = (unsigned)decrypt->blocksize;
+ uint8_t buf[PGP_MAX_BLOCK_SIZE + 2] = "";
+
+ pgp_reader_push_decrypt(stream, decrypt, region);
+
+ pgp_init_subregion(&encregion, NULL);
+ encregion.length = b + 2;
+
+ if (!exact_limread(buf, b + 2, &encregion, stream)) {
+ return 0;
+ }
+ if (buf[b - 2] != buf[b] || buf[b - 1] != buf[b + 1]) {
+ pgp_reader_pop_decrypt(stream);
+ PGP_ERROR_4(&stream->errors,
+ PGP_E_PROTO_BAD_SYMMETRIC_DECRYPT,
+ "Bad symmetric decrypt (%02x%02x vs %02x%02x)",
+ buf[b - 2], buf[b - 1], buf[b], buf[b + 1]);
+ return 0;
+ }
+ if (tag == PGP_PTAG_CT_SE_DATA_BODY) {
+ decrypt->decrypt_resync(decrypt);
+ decrypt->block_encrypt(decrypt, decrypt->civ,
+ decrypt->civ);
+ }
+ r = pgp_parse(stream, !printerrors);
+
+ pgp_reader_pop_decrypt(stream);
+ } else {
+ pgp_packet_t pkt;
+
+ while (region->readc < region->length) {
+ unsigned len;
+
+ len = region->length - region->readc;
+ if (len > sizeof(pkt.u.se_data_body.data))
+ len = sizeof(pkt.u.se_data_body.data);
+
+ if (!limread(pkt.u.se_data_body.data, len,
+ region, stream)) {
+ return 0;
+ }
+ pkt.u.se_data_body.length = len;
+ CALLBACK(tag, &stream->cbinfo, &pkt);
+ }
+ }
+
+ return r;
+}
+
+static int
+decrypt_se_ip_data(pgp_content_enum tag, pgp_region_t *region,
+ pgp_stream_t *stream)
+{
+ pgp_crypt_t *decrypt;
+ const int printerrors = 1;
+ int r = 1;
+
+ decrypt = pgp_get_decrypt(stream);
+ if (decrypt) {
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "decrypt_se_ip_data: decrypt\n");
+ }
+ pgp_reader_push_decrypt(stream, decrypt, region);
+ pgp_reader_push_se_ip_data(stream, decrypt, region);
+
+ r = pgp_parse(stream, !printerrors);
+
+ pgp_reader_pop_se_ip_data(stream);
+ pgp_reader_pop_decrypt(stream);
+ } else {
+ pgp_packet_t pkt;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "decrypt_se_ip_data: no decrypt\n");
+ }
+ while (region->readc < region->length) {
+ unsigned len;
+
+ len = region->length - region->readc;
+ if (len > sizeof(pkt.u.se_data_body.data)) {
+ len = sizeof(pkt.u.se_data_body.data);
+ }
+
+ if (!limread(pkt.u.se_data_body.data,
+ len, region, stream)) {
+ return 0;
+ }
+
+ pkt.u.se_data_body.length = len;
+
+ CALLBACK(tag, &stream->cbinfo, &pkt);
+ }
+ }
+
+ return r;
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Read a Symmetrically Encrypted packet
+*/
+static int
+parse_se_data(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+
+ /* there's no info to go with this, so just announce it */
+ CALLBACK(PGP_PTAG_CT_SE_DATA_HEADER, &stream->cbinfo, &pkt);
+
+ /*
+ * The content of an encrypted data packet is more OpenPGP packets
+ * once decrypted, so recursively handle them
+ */
+ return decrypt_se_data(PGP_PTAG_CT_SE_DATA_BODY, region, stream);
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Read a Symmetrically Encrypted Integrity Protected packet
+*/
+static int
+parse_se_ip_data(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+ uint8_t c = 0x0;
+
+ if (!limread(&c, 1, region, stream)) {
+ return 0;
+ }
+ pkt.u.se_ip_data_header = c;
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "parse_se_ip_data: data header %d\n", c);
+ }
+ if (pkt.u.se_ip_data_header != PGP_SE_IP_DATA_VERSION) {
+ (void) fprintf(stderr, "parse_se_ip_data: bad version\n");
+ return 0;
+ }
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "parse_se_ip_data: region %d,%d\n",
+ region->readc, region->length);
+ hexdump(stderr, "compressed region", stream->virtualpkt, stream->virtualc);
+ }
+ /*
+ * The content of an encrypted data packet is more OpenPGP packets
+ * once decrypted, so recursively handle them
+ */
+ return decrypt_se_ip_data(PGP_PTAG_CT_SE_IP_DATA_BODY, region, stream);
+}
+
+/**
+ \ingroup Core_ReadPackets
+ \brief Read a MDC packet
+*/
+static int
+parse_mdc(pgp_region_t *region, pgp_stream_t *stream)
+{
+ pgp_packet_t pkt;
+
+ pkt.u.mdc.length = PGP_SHA1_HASH_SIZE;
+ if ((pkt.u.mdc.data = calloc(1, PGP_SHA1_HASH_SIZE)) == NULL) {
+ (void) fprintf(stderr, "parse_mdc: bad alloc\n");
+ return 0;
+ }
+ if (!limread(pkt.u.mdc.data, PGP_SHA1_HASH_SIZE, region, stream)) {
+ return 0;
+ }
+ CALLBACK(PGP_PTAG_CT_MDC, &stream->cbinfo, &pkt);
+ free(pkt.u.mdc.data);
+ return 1;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ * \brief Parse one packet.
+ *
+ * This function parses the packet tag. It computes the value of the
+ * content tag and then calls the appropriate function to handle the
+ * content.
+ *
+ * \param *stream How to parse
+ * \param *pktlen On return, will contain number of bytes in packet
+ * \return 1 on success, 0 on error, -1 on EOF */
+static int
+parse_packet(pgp_stream_t *stream, uint32_t *pktlen)
+{
+ pgp_packet_t pkt;
+ pgp_region_t region;
+ uint8_t ptag;
+ unsigned indeterminate = 0;
+ int ret;
+
+ pkt.u.ptag.position = stream->readinfo.position;
+
+ ret = base_read(&ptag, 1, stream);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr,
+ "parse_packet: base_read returned %d, ptag %d\n",
+ ret, ptag);
+ }
+
+ /* errors in the base read are effectively EOF. */
+ if (ret <= 0) {
+ return -1;
+ }
+
+ *pktlen = 0;
+
+ if (!(ptag & PGP_PTAG_ALWAYS_SET)) {
+ pkt.u.error = "Format error (ptag bit not set)";
+ CALLBACK(PGP_PARSER_ERROR, &stream->cbinfo, &pkt);
+ return 0;
+ }
+ pkt.u.ptag.new_format = !!(ptag & PGP_PTAG_NEW_FORMAT);
+ if (pkt.u.ptag.new_format) {
+ pkt.u.ptag.type = (ptag & PGP_PTAG_NF_CONTENT_TAG_MASK);
+ pkt.u.ptag.length_type = 0;
+ if (!read_new_length(&pkt.u.ptag.length, stream)) {
+ return 0;
+ }
+ } else {
+ unsigned rb;
+
+ rb = 0;
+ pkt.u.ptag.type = ((unsigned)ptag &
+ PGP_PTAG_OF_CONTENT_TAG_MASK)
+ >> PGP_PTAG_OF_CONTENT_TAG_SHIFT;
+ pkt.u.ptag.length_type = ptag & PGP_PTAG_OF_LENGTH_TYPE_MASK;
+ switch (pkt.u.ptag.length_type) {
+ case PGP_PTAG_OLD_LEN_1:
+ rb = _read_scalar(&pkt.u.ptag.length, 1, stream);
+ break;
+
+ case PGP_PTAG_OLD_LEN_2:
+ rb = _read_scalar(&pkt.u.ptag.length, 2, stream);
+ break;
+
+ case PGP_PTAG_OLD_LEN_4:
+ rb = _read_scalar(&pkt.u.ptag.length, 4, stream);
+ break;
+
+ case PGP_PTAG_OLD_LEN_INDETERMINATE:
+ pkt.u.ptag.length = 0;
+ indeterminate = 1;
+ rb = 1;
+ break;
+ }
+ if (!rb) {
+ return 0;
+ }
+ }
+
+ CALLBACK(PGP_PARSER_PTAG, &stream->cbinfo, &pkt);
+
+ pgp_init_subregion(®ion, NULL);
+ region.length = pkt.u.ptag.length;
+ region.indeterminate = indeterminate;
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "parse_packet: type %u\n",
+ pkt.u.ptag.type);
+ }
+ switch (pkt.u.ptag.type) {
+ case PGP_PTAG_CT_SIGNATURE:
+ ret = parse_sig(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_PUBLIC_KEY:
+ case PGP_PTAG_CT_PUBLIC_SUBKEY:
+ ret = parse_pubkey((pgp_content_enum)pkt.u.ptag.type, ®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_TRUST:
+ ret = parse_trust(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_USER_ID:
+ ret = parse_userid(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_COMPRESSED:
+ ret = parse_compressed(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_1_PASS_SIG:
+ ret = parse_one_pass(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_LITDATA:
+ ret = parse_litdata(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_USER_ATTR:
+ ret = parse_userattr(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_SECRET_KEY:
+ ret = parse_seckey(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_SECRET_SUBKEY:
+ ret = parse_seckey(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_PK_SESSION_KEY:
+ ret = parse_pk_sesskey(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_SE_DATA:
+ ret = parse_se_data(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_SE_IP_DATA:
+ ret = parse_se_ip_data(®ion, stream);
+ break;
+
+ case PGP_PTAG_CT_MDC:
+ ret = parse_mdc(®ion, stream);
+ break;
+
+ default:
+ PGP_ERROR_1(&stream->errors, PGP_E_P_UNKNOWN_TAG,
+ "Unknown content tag 0x%x",
+ pkt.u.ptag.type);
+ ret = 0;
+ }
+
+ /* Ensure that the entire packet has been consumed */
+
+ if (region.length != region.readc && !region.indeterminate) {
+ if (!consume_packet(®ion, stream, 0)) {
+ ret = -1;
+ }
+ }
+
+ /* also consume it if there's been an error? */
+ /* \todo decide what to do about an error on an */
+ /* indeterminate packet */
+ if (ret == 0) {
+ if (!consume_packet(®ion, stream, 0)) {
+ ret = -1;
+ }
+ }
+ /* set pktlen */
+
+ *pktlen = stream->readinfo.alength;
+
+ /* do callback on entire packet, if desired and there was no error */
+
+ if (ret > 0 && stream->readinfo.accumulate) {
+ pkt.u.packet.length = stream->readinfo.alength;
+ pkt.u.packet.raw = stream->readinfo.accumulated;
+ stream->readinfo.accumulated = NULL;
+ stream->readinfo.asize = 0;
+ CALLBACK(PGP_PARSER_PACKET_END, &stream->cbinfo, &pkt);
+ }
+ stream->readinfo.alength = 0;
+
+ return (ret < 0) ? -1 : (ret) ? 1 : 0;
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ *
+ * \brief Parse packets from an input stream until EOF or error.
+ *
+ * \details Setup the necessary parsing configuration in "stream"
+ * before calling pgp_parse().
+ *
+ * That information includes :
+ *
+ * - a "reader" function to be used to get the data to be parsed
+ *
+ * - a "callback" function to be called when this library has identified
+ * a parseable object within the data
+ *
+ * - whether the calling function wants the signature subpackets
+ * returned raw, parsed or not at all.
+ *
+ * After returning, stream->errors holds any errors encountered while parsing.
+ *
+ * \param stream Parsing configuration
+ * \return 1 on success in all packets, 0 on error in any packet
+ *
+ * \sa CoreAPI Overview
+ *
+ * \sa pgp_print_errors()
+ *
+ */
+
+int
+pgp_parse(pgp_stream_t *stream, const int perrors)
+{
+ uint32_t pktlen;
+ int r;
+
+ do {
+ r = parse_packet(stream, &pktlen);
+ } while (r != -1);
+ if (perrors) {
+ pgp_print_errors(stream->errors);
+ }
+ return (stream->errors == NULL);
+}
+
+/**
+ * \ingroup Core_ReadPackets
+ *
+ * \brief Specifies whether one or more signature
+ * subpacket types should be returned parsed; or raw; or ignored.
+ *
+ * \param stream Pointer to previously allocated structure
+ * \param tag Packet tag. PGP_PTAG_SS_ALL for all SS tags; or one individual signature subpacket tag
+ * \param type Parse type
+ * \todo Make all packet types optional, not just subpackets */
+void
+pgp_parse_options(pgp_stream_t *stream,
+ pgp_content_enum tag,
+ pgp_parse_type_t type)
+{
+ unsigned t7;
+ unsigned t8;
+
+ if (tag == PGP_PTAG_SS_ALL) {
+ int n;
+
+ for (n = 0; n < 256; ++n) {
+ pgp_parse_options(stream,
+ PGP_PTAG_SIG_SUBPKT_BASE + n,
+ type);
+ }
+ return;
+ }
+ if (tag < PGP_PTAG_SIG_SUBPKT_BASE ||
+ tag > PGP_PTAG_SIG_SUBPKT_BASE + NTAGS - 1) {
+ (void) fprintf(stderr, "pgp_parse_options: bad tag\n");
+ return;
+ }
+ t8 = (tag - PGP_PTAG_SIG_SUBPKT_BASE) / 8;
+ t7 = 1 << ((tag - PGP_PTAG_SIG_SUBPKT_BASE) & 7);
+ switch (type) {
+ case PGP_PARSE_RAW:
+ stream->ss_raw[t8] |= t7;
+ stream->ss_parsed[t8] &= ~t7;
+ break;
+
+ case PGP_PARSE_PARSED:
+ stream->ss_raw[t8] &= ~t7;
+ stream->ss_parsed[t8] |= t7;
+ break;
+
+ case PGP_PARSE_IGNORE:
+ stream->ss_raw[t8] &= ~t7;
+ stream->ss_parsed[t8] &= ~t7;
+ break;
+ }
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Free pgp_stream_t struct and its contents
+*/
+void
+pgp_stream_delete(pgp_stream_t *stream)
+{
+ pgp_cbdata_t *cbinfo;
+ pgp_cbdata_t *next;
+
+ for (cbinfo = stream->cbinfo.next; cbinfo; cbinfo = next) {
+ next = cbinfo->next;
+ free(cbinfo);
+ }
+ if (stream->readinfo.destroyer) {
+ stream->readinfo.destroyer(&stream->readinfo);
+ }
+ pgp_free_errors(stream->errors);
+ if (stream->readinfo.accumulated) {
+ free(stream->readinfo.accumulated);
+ }
+ free(stream);
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Returns the parse_info's reader_info
+\return Pointer to the reader_info inside the parse_info
+*/
+pgp_reader_t *
+pgp_readinfo(pgp_stream_t *stream)
+{
+ return &stream->readinfo;
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Sets the parse_info's callback
+This is used when adding the first callback in a stack of callbacks.
+\sa pgp_callback_push()
+*/
+
+void
+pgp_set_callback(pgp_stream_t *stream, pgp_cbfunc_t *cb, void *arg)
+{
+ stream->cbinfo.cbfunc = cb;
+ stream->cbinfo.arg = arg;
+ stream->cbinfo.errors = &stream->errors;
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Adds a further callback to a stack of callbacks
+\sa pgp_set_callback()
+*/
+void
+pgp_callback_push(pgp_stream_t *stream, pgp_cbfunc_t *cb, void *arg)
+{
+ pgp_cbdata_t *cbinfo;
+
+ if ((cbinfo = calloc(1, sizeof(*cbinfo))) == NULL) {
+ (void) fprintf(stderr, "pgp_callback_push: bad alloc\n");
+ return;
+ }
+ (void) memcpy(cbinfo, &stream->cbinfo, sizeof(*cbinfo));
+ cbinfo->io = stream->io;
+ stream->cbinfo.next = cbinfo;
+ pgp_set_callback(stream, cb, arg);
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Returns callback's arg
+*/
+void *
+pgp_callback_arg(pgp_cbdata_t *cbinfo)
+{
+ return cbinfo->arg;
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Returns callback's errors
+*/
+void *
+pgp_callback_errors(pgp_cbdata_t *cbinfo)
+{
+ return cbinfo->errors;
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Calls the parse_cb_info's callback if present
+\return Return value from callback, if present; else PGP_FINISHED
+*/
+pgp_cb_ret_t
+pgp_callback(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ return (cbinfo->cbfunc) ? cbinfo->cbfunc(pkt, cbinfo) : PGP_FINISHED;
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Calls the next callback in the stack
+\return Return value from callback
+*/
+pgp_cb_ret_t
+pgp_stacked_callback(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ return pgp_callback(pkt, cbinfo->next);
+}
+
+/**
+\ingroup Core_ReadPackets
+\brief Returns the parse_info's errors
+\return parse_info's errors
+*/
+pgp_error_t *
+pgp_stream_get_errors(pgp_stream_t *stream)
+{
+ return stream->errors;
+}
+
+pgp_crypt_t *
+pgp_get_decrypt(pgp_stream_t *stream)
+{
+ return (stream->decrypt.alg) ? &stream->decrypt : NULL;
+}
diff --git a/libs/netpgp/src/lib/packet-parse.h b/libs/netpgp/src/lib/packet-parse.h
new file mode 100644
index 00000000..a62aced6
--- /dev/null
+++ b/libs/netpgp/src/lib/packet-parse.h
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ * Parser for OpenPGP packets - headers.
+ */
+
+#ifndef PACKET_PARSE_H_
+#define PACKET_PARSE_H_
+
+#include "types.h"
+#include "packet.h"
+
+/** pgp_region_t */
+typedef struct pgp_region_t {
+ struct pgp_region_t *parent;
+ unsigned length;
+ unsigned readc; /* length read */
+ unsigned last_read;
+ /* length of last read, only valid in deepest child */
+ unsigned indeterminate:1;
+} pgp_region_t;
+
+void pgp_init_subregion(pgp_region_t *, pgp_region_t *);
+
+/** pgp_cb_ret_t */
+typedef enum {
+ PGP_RELEASE_MEMORY,
+ PGP_KEEP_MEMORY,
+ PGP_FINISHED
+} pgp_cb_ret_t;
+
+typedef struct pgp_cbdata_t pgp_cbdata_t;
+
+typedef pgp_cb_ret_t pgp_cbfunc_t(const pgp_packet_t *,
+ pgp_cbdata_t *);
+
+pgp_cb_ret_t
+get_passphrase_cb(const pgp_packet_t *, pgp_cbdata_t *);
+
+typedef struct pgp_stream_t pgp_stream_t;
+typedef struct pgp_reader_t pgp_reader_t;
+typedef struct pgp_cryptinfo_t pgp_cryptinfo_t;
+
+/*
+ A reader MUST read at least one byte if it can, and should read up
+ to the number asked for. Whether it reads more for efficiency is
+ its own decision, but if it is a stacked reader it should never
+ read more than the length of the region it operates in (which it
+ would have to be given when it is stacked).
+
+ If a read is short because of EOF, then it should return the short
+ read (obviously this will be zero on the second attempt, if not the
+ first). Because a reader is not obliged to do a full read, only a
+ zero return can be taken as an indication of EOF.
+
+ If there is an error, then the callback should be notified, the
+ error stacked, and -1 should be returned.
+
+ Note that although length is a size_t, a reader will never be asked
+ to read more than INT_MAX in one go.
+
+ */
+typedef int pgp_reader_func_t(pgp_stream_t *, void *, size_t, pgp_error_t **,
+ pgp_reader_t *, pgp_cbdata_t *);
+
+typedef void pgp_reader_destroyer_t(pgp_reader_t *);
+
+void pgp_stream_delete(pgp_stream_t *);
+pgp_error_t *pgp_stream_get_errors(pgp_stream_t *);
+pgp_crypt_t *pgp_get_decrypt(pgp_stream_t *);
+
+void pgp_set_callback(pgp_stream_t *, pgp_cbfunc_t *, void *);
+void pgp_callback_push(pgp_stream_t *, pgp_cbfunc_t *, void *);
+void *pgp_callback_arg(pgp_cbdata_t *);
+void *pgp_callback_errors(pgp_cbdata_t *);
+void pgp_reader_set(pgp_stream_t *, pgp_reader_func_t *,
+ pgp_reader_destroyer_t *, void *);
+void pgp_reader_push(pgp_stream_t *, pgp_reader_func_t *,
+ pgp_reader_destroyer_t *, void *);
+void pgp_reader_pop(pgp_stream_t *);
+
+void *pgp_reader_get_arg(pgp_reader_t *);
+
+pgp_cb_ret_t pgp_callback(const pgp_packet_t *,
+ pgp_cbdata_t *);
+pgp_cb_ret_t pgp_stacked_callback(const pgp_packet_t *,
+ pgp_cbdata_t *);
+pgp_reader_t *pgp_readinfo(pgp_stream_t *);
+
+int pgp_parse(pgp_stream_t *, const int);
+
+/** Used to specify whether subpackets should be returned raw, parsed
+* or ignored. */
+typedef enum {
+ PGP_PARSE_RAW, /* Callback Raw */
+ PGP_PARSE_PARSED, /* Callback Parsed */
+ PGP_PARSE_IGNORE /* Don't callback */
+} pgp_parse_type_t;
+
+void pgp_parse_options(pgp_stream_t *, pgp_content_enum,
+ pgp_parse_type_t);
+
+unsigned pgp_limited_read(pgp_stream_t *, uint8_t *, size_t, pgp_region_t *,
+ pgp_error_t **, pgp_reader_t *,
+ pgp_cbdata_t *);
+unsigned pgp_stacked_limited_read(pgp_stream_t *, uint8_t *, unsigned,
+ pgp_region_t *, pgp_error_t **,
+ pgp_reader_t *, pgp_cbdata_t *);
+void pgp_parse_hash_init(pgp_stream_t *, pgp_hash_alg_t,
+ const uint8_t *);
+void pgp_parse_hash_data(pgp_stream_t *, const void *, size_t);
+void pgp_parse_hash_finish(pgp_stream_t *);
+pgp_hash_t *pgp_parse_hash_find(pgp_stream_t *, const uint8_t *);
+
+pgp_reader_func_t pgp_stacked_read;
+
+int pgp_decompress(pgp_region_t *, pgp_stream_t *,
+ pgp_compression_type_t);
+unsigned pgp_writez(pgp_output_t *, const uint8_t *,
+ const unsigned);
+
+#endif /* PACKET_PARSE_H_ */
diff --git a/libs/netpgp/src/lib/packet-print.c b/libs/netpgp/src/lib/packet-print.c
new file mode 100644
index 00000000..da9b26c1
--- /dev/null
+++ b/libs/netpgp/src/lib/packet-print.c
@@ -0,0 +1,1456 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * ! \file \brief Standard API print functions
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: packet-print.c,v 1.42 2012/02/22 06:29:40 agc Exp $");
+#endif
+
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#include "crypto.h"
+#include "keyring.h"
+#include "packet-show.h"
+#include "signature.h"
+#include "readerwriter.h"
+#include "netpgpdefs.h"
+#include "netpgpsdk.h"
+#include "packet.h"
+#include "netpgpdigest.h"
+#include "mj.h"
+
+/* static functions */
+
+static void
+print_indent(int indent)
+{
+ int i;
+
+ for (i = 0; i < indent; i++) {
+ printf(" ");
+ }
+}
+
+static void
+print_name(int indent, const char *name)
+{
+ print_indent(indent);
+ if (name) {
+ printf("%s: ", name);
+ }
+}
+
+static void
+print_hexdump(int indent, const char *name, const uint8_t *data, unsigned len)
+{
+ print_name(indent, name);
+ hexdump(stdout, NULL, data, len);
+}
+
+static void
+hexdump_data(int indent, const char *name, const uint8_t *data, unsigned len)
+{
+ print_name(indent, name);
+ hexdump(stdout, NULL, data, len);
+}
+
+static void
+print_uint(int indent, const char *name, unsigned val)
+{
+ print_name(indent, name);
+ printf("%u\n", val);
+}
+
+static void
+showtime(const char *name, time_t t)
+{
+ printf("%s=%" PRItime "d (%.24s)", name, (long long) t, ctime(&t));
+}
+
+static void
+print_time(int indent, const char *name, time_t t)
+{
+ print_indent(indent);
+ printf("%s: ", name);
+ showtime("time", t);
+ printf("\n");
+}
+
+static void
+print_string_and_value(int indent, const char *name, const char *str, uint8_t value)
+{
+ print_name(indent, name);
+ printf("%s (0x%x)\n", str, value);
+}
+
+static void
+print_tagname(int indent, const char *str)
+{
+ print_indent(indent);
+ printf("%s packet\n", str);
+}
+
+static void
+print_data(int indent, const char *name, const pgp_data_t *data)
+{
+ print_hexdump(indent, name, data->contents, (unsigned)data->len);
+}
+
+static void
+print_bn(int indent, const char *name, const BIGNUM *bn)
+{
+ print_indent(indent);
+ printf("%s=", name);
+ if (bn) {
+ BN_print_fp(stdout, bn);
+ putchar('\n');
+ } else {
+ puts("(unset)");
+ }
+}
+
+static void
+print_packet_hex(const pgp_subpacket_t *pkt)
+{
+ hexdump(stdout, "packet contents:", pkt->raw, pkt->length);
+}
+
+static void
+print_escaped(const uint8_t *data, size_t length)
+{
+ while (length-- > 0) {
+ if ((*data >= 0x20 && *data < 0x7f && *data != '%') ||
+ *data == '\n') {
+ putchar(*data);
+ } else {
+ printf("%%%02x", *data);
+ }
+ ++data;
+ }
+}
+
+static void
+print_string(int indent, const char *name, const char *str)
+{
+ print_name(indent, name);
+ print_escaped((const uint8_t *) str, strlen(str));
+ putchar('\n');
+}
+
+static void
+print_utf8_string(int indent, const char *name, const uint8_t *str)
+{
+ /* \todo Do this better for non-English character sets */
+ print_string(indent, name, (const char *) str);
+}
+
+static void
+print_duration(int indent, const char *name, time_t t)
+{
+ int mins, hours, days, years;
+
+ print_indent(indent);
+ printf("%s: ", name);
+ printf("duration %" PRItime "d seconds", (long long) t);
+
+ mins = (int)(t / 60);
+ hours = mins / 60;
+ days = hours / 24;
+ years = days / 365;
+
+ printf(" (approx. ");
+ if (years) {
+ printf("%d %s", years, years == 1 ? "year" : "years");
+ } else if (days) {
+ printf("%d %s", days, days == 1 ? "day" : "days");
+ } else if (hours) {
+ printf("%d %s", hours, hours == 1 ? "hour" : "hours");
+ }
+ printf(")\n");
+}
+
+static void
+print_boolean(int indent, const char *name, uint8_t boolval)
+{
+ print_name(indent, name);
+ printf("%s\n", (boolval) ? "Yes" : "No");
+}
+
+static void
+print_text_breakdown(int indent, pgp_text_t *text)
+{
+ const char *prefix = ".. ";
+ unsigned i;
+
+ /* these were recognised */
+ for (i = 0; i < text->known.used; i++) {
+ print_indent(indent);
+ printf("%s", prefix);
+ printf("%s\n", text->known.strings[i]);
+ }
+ /*
+ * these were not recognised. the strings will contain the hex value
+ * of the unrecognised value in string format - see
+ * process_octet_str()
+ */
+ if (text->unknown.used) {
+ printf("\n");
+ print_indent(indent);
+ printf("Not Recognised: ");
+ }
+ for (i = 0; i < text->unknown.used; i++) {
+ print_indent(indent);
+ printf("%s", prefix);
+ printf("%s\n", text->unknown.strings[i]);
+ }
+}
+
+static void
+print_headers(const pgp_headers_t *h)
+{
+ unsigned i;
+
+ for (i = 0; i < h->headerc; ++i) {
+ printf("%s=%s\n", h->headers[i].key, h->headers[i].value);
+ }
+}
+
+static void
+print_block(int indent, const char *name, const uint8_t *str, size_t length)
+{
+ int o = (int)length;
+
+ print_indent(indent);
+ printf(">>>>> %s >>>>>\n", name);
+
+ print_indent(indent);
+ for (; length > 0; --length) {
+ if (*str >= 0x20 && *str < 0x7f && *str != '%') {
+ putchar(*str);
+ } else if (*str == '\n') {
+ putchar(*str);
+ print_indent(indent);
+ } else {
+ printf("%%%02x", *str);
+ }
+ ++str;
+ }
+ if (o && str[-1] != '\n') {
+ putchar('\n');
+ print_indent(indent);
+ fputs("[no newline]", stdout);
+ } else {
+ print_indent(indent);
+ }
+ printf("<<<<< %s <<<<<\n", name);
+}
+
+/* return the number of bits in the public key */
+static int
+numkeybits(const pgp_pubkey_t *pubkey)
+{
+ switch(pubkey->alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ return BN_num_bytes(pubkey->key.rsa.n) * 8;
+ case PGP_PKA_DSA:
+ switch(BN_num_bytes(pubkey->key.dsa.q)) {
+ case 20:
+ return 1024;
+ case 28:
+ return 2048;
+ case 32:
+ return 3072;
+ default:
+ return 0;
+ }
+ case PGP_PKA_ELGAMAL:
+ return BN_num_bytes(pubkey->key.elgamal.y) * 8;
+ default:
+ return -1;
+ }
+}
+
+/* return the hexdump as a string */
+static char *
+strhexdump(char *dest, const uint8_t *src, size_t length, const char *sep)
+{
+ unsigned i;
+ int n;
+
+ for (n = 0, i = 0 ; i < length ; i += 2) {
+ n += snprintf(&dest[n], 3, "%02x", *src++);
+ n += snprintf(&dest[n], 10, "%02x%s", *src++, sep);
+ }
+ return dest;
+}
+
+/* return the time as a string */
+static char *
+ptimestr(char *dest, size_t size, time_t t)
+{
+ struct tm *tm;
+
+ tm = gmtime(&t);
+ (void) snprintf(dest, size, "%04d-%02d-%02d",
+ tm->tm_year + 1900,
+ tm->tm_mon + 1,
+ tm->tm_mday);
+ return dest;
+}
+
+/* print the sub key binding signature info */
+static int
+psubkeybinding(char *buf, size_t size, const pgp_key_t *key, const char *expired)
+{
+ char keyid[512];
+ char t[32];
+
+ return snprintf(buf, size, "encryption %d/%s %s %s %s\n",
+ numkeybits(&key->enckey),
+ pgp_show_pka(key->enckey.alg),
+ strhexdump(keyid, key->encid, PGP_KEY_ID_SIZE, ""),
+ ptimestr(t, sizeof(t), key->enckey.birthtime),
+ expired);
+}
+
+static int
+isrevoked(const pgp_key_t *key, unsigned uid)
+{
+ unsigned r;
+
+ for (r = 0 ; r < key->revokec ; r++) {
+ if (key->revokes[r].uid == uid) {
+ return r;
+ }
+ }
+ return -1;
+}
+
+#ifndef KB
+#define KB(x) ((x) * 1024)
+#endif
+
+/* print into a string (malloc'ed) the pubkeydata */
+int
+pgp_sprint_keydata(pgp_io_t *io, const pgp_keyring_t *keyring,
+ const pgp_key_t *key, char **buf, const char *header,
+ const pgp_pubkey_t *pubkey, const int psigs)
+{
+ const pgp_key_t *trustkey;
+ unsigned from;
+ unsigned i;
+ unsigned j;
+ time_t now;
+ char uidbuf[KB(128)];
+ char keyid[PGP_KEY_ID_SIZE * 3];
+ char fp[(PGP_FINGERPRINT_SIZE * 3) + 1];
+ char expired[128];
+ char t[32];
+ int cc;
+ int n;
+ int r;
+
+ if (key == NULL || key->revoked) {
+ return -1;
+ }
+ now = time(NULL);
+ if (pubkey->duration > 0) {
+ cc = snprintf(expired, sizeof(expired),
+ (pubkey->birthtime + pubkey->duration < now) ?
+ "[EXPIRED " : "[EXPIRES ");
+ ptimestr(&expired[cc], sizeof(expired) - cc,
+ pubkey->birthtime + pubkey->duration);
+ cc += 10;
+ cc += snprintf(&expired[cc], sizeof(expired) - cc, "]");
+ } else {
+ expired[0] = 0x0;
+ }
+ for (i = 0, n = 0; i < key->uidc; i++) {
+ if ((r = isrevoked(key, i)) >= 0 &&
+ key->revokes[r].code == PGP_REVOCATION_COMPROMISED) {
+ continue;
+ }
+ n += snprintf(&uidbuf[n], sizeof(uidbuf) - n, "uid%s%s%s\n",
+ (psigs) ? " " : " ",
+ key->uids[i],
+ (isrevoked(key, i) >= 0) ? " [REVOKED]" : "");
+ for (j = 0 ; j < key->subsigc ; j++) {
+ if (psigs) {
+ if (key->subsigs[j].uid != i) {
+ continue;
+ }
+ } else {
+ if (!(key->subsigs[j].sig.info.version == 4 &&
+ key->subsigs[j].sig.info.type == PGP_SIG_SUBKEY &&
+ i == key->uidc - 1)) {
+ continue;
+ }
+ }
+ from = 0;
+ trustkey = pgp_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from, NULL);
+ if (key->subsigs[j].sig.info.version == 4 &&
+ key->subsigs[j].sig.info.type == PGP_SIG_SUBKEY) {
+ psubkeybinding(&uidbuf[n], sizeof(uidbuf) - n, key, expired);
+ } else {
+ n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
+ "sig %s %s %s\n",
+ strhexdump(keyid, key->subsigs[j].sig.info.signer_id, PGP_KEY_ID_SIZE, ""),
+ ptimestr(t, sizeof(t), key->subsigs[j].sig.info.birthtime),
+ (trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "[unknown]");
+ }
+ }
+ }
+ return pgp_asprintf(buf, "%s %d/%s %s %s %s\nKey fingerprint: %s\n%s",
+ header,
+ numkeybits(pubkey),
+ pgp_show_pka(pubkey->alg),
+ strhexdump(keyid, key->sigid, PGP_KEY_ID_SIZE, ""),
+ ptimestr(t, sizeof(t), pubkey->birthtime),
+ expired,
+ strhexdump(fp, key->sigfingerprint.fingerprint, key->sigfingerprint.length, " "),
+ uidbuf);
+}
+
+/* return the key info as a JSON encoded string */
+int
+pgp_sprint_mj(pgp_io_t *io, const pgp_keyring_t *keyring,
+ const pgp_key_t *key, mj_t *keyjson, const char *header,
+ const pgp_pubkey_t *pubkey, const int psigs)
+{
+ const pgp_key_t *trustkey;
+ unsigned from;
+ unsigned i;
+ unsigned j;
+ mj_t sub_obj;
+ char keyid[PGP_KEY_ID_SIZE * 3];
+ char fp[(PGP_FINGERPRINT_SIZE * 3) + 1];
+ int r;
+
+ if (key == NULL || key->revoked) {
+ return -1;
+ }
+ (void) memset(keyjson, 0x0, sizeof(*keyjson));
+ mj_create(keyjson, "object");
+ mj_append_field(keyjson, "header", "string", header, -1);
+ mj_append_field(keyjson, "key bits", "integer", (int64_t) numkeybits(pubkey));
+ mj_append_field(keyjson, "pka", "string", pgp_show_pka(pubkey->alg), -1);
+ mj_append_field(keyjson, "key id", "string", strhexdump(keyid, key->sigid, PGP_KEY_ID_SIZE, ""), -1);
+ mj_append_field(keyjson, "fingerprint", "string",
+ strhexdump(fp, key->sigfingerprint.fingerprint, key->sigfingerprint.length, " "), -1);
+ mj_append_field(keyjson, "birthtime", "integer", pubkey->birthtime);
+ mj_append_field(keyjson, "duration", "integer", pubkey->duration);
+ for (i = 0; i < key->uidc; i++) {
+ if ((r = isrevoked(key, i)) >= 0 &&
+ key->revokes[r].code == PGP_REVOCATION_COMPROMISED) {
+ continue;
+ }
+ (void) memset(&sub_obj, 0x0, sizeof(sub_obj));
+ mj_create(&sub_obj, "array");
+ mj_append(&sub_obj, "string", key->uids[i], -1);
+ mj_append(&sub_obj, "string", (r >= 0) ? "[REVOKED]" : "", -1);
+ mj_append_field(keyjson, "uid", "array", &sub_obj);
+ mj_delete(&sub_obj);
+ for (j = 0 ; j < key->subsigc ; j++) {
+ if (psigs) {
+ if (key->subsigs[j].uid != i) {
+ continue;
+ }
+ } else {
+ if (!(key->subsigs[j].sig.info.version == 4 &&
+ key->subsigs[j].sig.info.type == PGP_SIG_SUBKEY &&
+ i == key->uidc - 1)) {
+ continue;
+ }
+ }
+ (void) memset(&sub_obj, 0x0, sizeof(sub_obj));
+ mj_create(&sub_obj, "array");
+ if (key->subsigs[j].sig.info.version == 4 &&
+ key->subsigs[j].sig.info.type == PGP_SIG_SUBKEY) {
+ mj_append(&sub_obj, "integer", (int64_t)numkeybits(&key->enckey));
+ mj_append(&sub_obj, "string",
+ (const char *)pgp_show_pka(key->enckey.alg), -1);
+ mj_append(&sub_obj, "string",
+ strhexdump(keyid, key->encid, PGP_KEY_ID_SIZE, ""), -1);
+ mj_append(&sub_obj, "integer", (int64_t)key->enckey.birthtime);
+ mj_append_field(keyjson, "encryption", "array", &sub_obj);
+ mj_delete(&sub_obj);
+ } else {
+ mj_append(&sub_obj, "string",
+ strhexdump(keyid, key->subsigs[j].sig.info.signer_id, PGP_KEY_ID_SIZE, ""), -1);
+ mj_append(&sub_obj, "integer",
+ (int64_t)(key->subsigs[j].sig.info.birthtime));
+ from = 0;
+ trustkey = pgp_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from, NULL);
+ mj_append(&sub_obj, "string",
+ (trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "[unknown]", -1);
+ mj_append_field(keyjson, "sig", "array", &sub_obj);
+ mj_delete(&sub_obj);
+ }
+ }
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ char *buf;
+
+ mj_asprint(&buf, keyjson, 1);
+ (void) fprintf(stderr, "pgp_sprint_mj: '%s'\n", buf);
+ free(buf);
+ }
+ return 1;
+}
+
+int
+pgp_hkp_sprint_keydata(pgp_io_t *io, const pgp_keyring_t *keyring,
+ const pgp_key_t *key, char **buf,
+ const pgp_pubkey_t *pubkey, const int psigs)
+{
+ const pgp_key_t *trustkey;
+ unsigned from;
+ unsigned i;
+ unsigned j;
+ char keyid[PGP_KEY_ID_SIZE * 3];
+ char uidbuf[KB(128)];
+ char fp[(PGP_FINGERPRINT_SIZE * 3) + 1];
+ int n;
+
+ if (key->revoked) {
+ return -1;
+ }
+ for (i = 0, n = 0; i < key->uidc; i++) {
+ n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
+ "uid:%lld:%lld:%s\n",
+ (long long)pubkey->birthtime,
+ (long long)pubkey->duration,
+ key->uids[i]);
+ for (j = 0 ; j < key->subsigc ; j++) {
+ if (psigs) {
+ if (key->subsigs[j].uid != i) {
+ continue;
+ }
+ } else {
+ if (!(key->subsigs[j].sig.info.version == 4 &&
+ key->subsigs[j].sig.info.type == PGP_SIG_SUBKEY &&
+ i == key->uidc - 1)) {
+ continue;
+ }
+ }
+ from = 0;
+ trustkey = pgp_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from, NULL);
+ if (key->subsigs[j].sig.info.version == 4 &&
+ key->subsigs[j].sig.info.type == PGP_SIG_SUBKEY) {
+ n += snprintf(&uidbuf[n], sizeof(uidbuf) - n, "sub:%d:%d:%s:%lld:%lld\n",
+ numkeybits(pubkey),
+ key->subsigs[j].sig.info.key_alg,
+ strhexdump(keyid, key->subsigs[j].sig.info.signer_id, PGP_KEY_ID_SIZE, ""),
+ (long long)(key->subsigs[j].sig.info.birthtime),
+ (long long)pubkey->duration);
+ } else {
+ n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
+ "sig:%s:%lld:%s\n",
+ strhexdump(keyid, key->subsigs[j].sig.info.signer_id, PGP_KEY_ID_SIZE, ""),
+ (long long)key->subsigs[j].sig.info.birthtime,
+ (trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "");
+ }
+ }
+ }
+ return pgp_asprintf(buf, "pub:%s:%d:%d:%lld:%lld\n%s",
+ strhexdump(fp, key->sigfingerprint.fingerprint, PGP_FINGERPRINT_SIZE, ""),
+ pubkey->alg,
+ numkeybits(pubkey),
+ (long long)pubkey->birthtime,
+ (long long)pubkey->duration,
+ uidbuf);
+}
+
+/* print the key data for a pub or sec key */
+void
+pgp_print_keydata(pgp_io_t *io, const pgp_keyring_t *keyring,
+ const pgp_key_t *key, const char *header,
+ const pgp_pubkey_t *pubkey, const int psigs)
+{
+ char *cp;
+
+ if (pgp_sprint_keydata(io, keyring, key, &cp, header, pubkey, psigs) >= 0) {
+ (void) fprintf(io->res, "%s", cp);
+ free(cp);
+ }
+}
+
+/**
+\ingroup Core_Print
+\param pubkey
+*/
+void
+pgp_print_pubkey(const pgp_pubkey_t *pubkey)
+{
+ printf("------- PUBLIC KEY ------\n");
+ print_uint(0, "Version", (unsigned)pubkey->version);
+ print_time(0, "Creation Time", pubkey->birthtime);
+ if (pubkey->version == PGP_V3) {
+ print_uint(0, "Days Valid", pubkey->days_valid);
+ }
+ print_string_and_value(0, "Algorithm", pgp_show_pka(pubkey->alg),
+ pubkey->alg);
+ switch (pubkey->alg) {
+ case PGP_PKA_DSA:
+ print_bn(0, "p", pubkey->key.dsa.p);
+ print_bn(0, "q", pubkey->key.dsa.q);
+ print_bn(0, "g", pubkey->key.dsa.g);
+ print_bn(0, "y", pubkey->key.dsa.y);
+ break;
+
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ print_bn(0, "n", pubkey->key.rsa.n);
+ print_bn(0, "e", pubkey->key.rsa.e);
+ break;
+
+ case PGP_PKA_ELGAMAL:
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ print_bn(0, "p", pubkey->key.elgamal.p);
+ print_bn(0, "g", pubkey->key.elgamal.g);
+ print_bn(0, "y", pubkey->key.elgamal.y);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_print_pubkey: Unusual algorithm\n");
+ }
+
+ printf("------- end of PUBLIC KEY ------\n");
+}
+
+int
+pgp_sprint_pubkey(const pgp_key_t *key, char *out, size_t outsize)
+{
+ char fp[(PGP_FINGERPRINT_SIZE * 3) + 1];
+ int cc;
+
+ cc = snprintf(out, outsize, "key=%s\nname=%s\ncreation=%lld\nexpiry=%lld\nversion=%d\nalg=%d\n",
+ strhexdump(fp, key->sigfingerprint.fingerprint, PGP_FINGERPRINT_SIZE, ""),
+ key->uids[key->uid0],
+ (long long)key->key.pubkey.birthtime,
+ (long long)key->key.pubkey.days_valid,
+ key->key.pubkey.version,
+ key->key.pubkey.alg);
+ switch (key->key.pubkey.alg) {
+ case PGP_PKA_DSA:
+ cc += snprintf(&out[cc], outsize - cc,
+ "p=%s\nq=%s\ng=%s\ny=%s\n",
+ BN_bn2hex(key->key.pubkey.key.dsa.p),
+ BN_bn2hex(key->key.pubkey.key.dsa.q),
+ BN_bn2hex(key->key.pubkey.key.dsa.g),
+ BN_bn2hex(key->key.pubkey.key.dsa.y));
+ break;
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ cc += snprintf(&out[cc], outsize - cc,
+ "n=%s\ne=%s\n",
+ BN_bn2hex(key->key.pubkey.key.rsa.n),
+ BN_bn2hex(key->key.pubkey.key.rsa.e));
+ break;
+ case PGP_PKA_ELGAMAL:
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ cc += snprintf(&out[cc], outsize - cc,
+ "p=%s\ng=%s\ny=%s\n",
+ BN_bn2hex(key->key.pubkey.key.elgamal.p),
+ BN_bn2hex(key->key.pubkey.key.elgamal.g),
+ BN_bn2hex(key->key.pubkey.key.elgamal.y));
+ break;
+ default:
+ (void) fprintf(stderr,
+ "pgp_print_pubkey: Unusual algorithm\n");
+ }
+ return cc;
+}
+
+/**
+\ingroup Core_Print
+\param type
+\param seckey
+*/
+static void
+print_seckey_verbose(const pgp_content_enum type,
+ const pgp_seckey_t *seckey)
+{
+ printf("------- SECRET KEY or ENCRYPTED SECRET KEY ------\n");
+ print_tagname(0, (type == PGP_PTAG_CT_SECRET_KEY) ?
+ "SECRET_KEY" :
+ "ENCRYPTED_SECRET_KEY");
+ /* pgp_print_pubkey(key); */
+ printf("S2K Usage: %d\n", seckey->s2k_usage);
+ if (seckey->s2k_usage != PGP_S2KU_NONE) {
+ printf("S2K Specifier: %d\n", seckey->s2k_specifier);
+ printf("Symmetric algorithm: %d (%s)\n", seckey->alg,
+ pgp_show_symm_alg(seckey->alg));
+ printf("Hash algorithm: %d (%s)\n", seckey->hash_alg,
+ pgp_show_hash_alg((uint8_t)seckey->hash_alg));
+ if (seckey->s2k_specifier != PGP_S2KS_SIMPLE) {
+ print_hexdump(0, "Salt", seckey->salt,
+ (unsigned)sizeof(seckey->salt));
+ }
+ if (seckey->s2k_specifier == PGP_S2KS_ITERATED_AND_SALTED) {
+ printf("Octet count: %u\n", seckey->octetc);
+ }
+ print_hexdump(0, "IV", seckey->iv, pgp_block_size(seckey->alg));
+ }
+ /* no more set if encrypted */
+ if (type == PGP_PTAG_CT_ENCRYPTED_SECRET_KEY) {
+ return;
+ }
+ switch (seckey->pubkey.alg) {
+ case PGP_PKA_RSA:
+ print_bn(0, "d", seckey->key.rsa.d);
+ print_bn(0, "p", seckey->key.rsa.p);
+ print_bn(0, "q", seckey->key.rsa.q);
+ print_bn(0, "u", seckey->key.rsa.u);
+ break;
+
+ case PGP_PKA_DSA:
+ print_bn(0, "x", seckey->key.dsa.x);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "print_seckey_verbose: unusual algorithm\n");
+ }
+ if (seckey->s2k_usage == PGP_S2KU_ENCRYPTED_AND_HASHED) {
+ print_hexdump(0, "Checkhash", seckey->checkhash,
+ PGP_CHECKHASH_SIZE);
+ } else {
+ printf("Checksum: %04x\n", seckey->checksum);
+ }
+ printf("------- end of SECRET KEY or ENCRYPTED SECRET KEY ------\n");
+}
+
+
+/**
+\ingroup Core_Print
+\param tag
+\param key
+*/
+static void
+print_pk_sesskey(pgp_content_enum tag,
+ const pgp_pk_sesskey_t * key)
+{
+ print_tagname(0, (tag == PGP_PTAG_CT_PK_SESSION_KEY) ?
+ "PUBLIC KEY SESSION KEY" :
+ "ENCRYPTED PUBLIC KEY SESSION KEY");
+ printf("Version: %d\n", key->version);
+ print_hexdump(0, "Key ID", key->key_id, (unsigned)sizeof(key->key_id));
+ printf("Algorithm: %d (%s)\n", key->alg,
+ pgp_show_pka(key->alg));
+ switch (key->alg) {
+ case PGP_PKA_RSA:
+ print_bn(0, "encrypted_m", key->params.rsa.encrypted_m);
+ break;
+
+ case PGP_PKA_ELGAMAL:
+ print_bn(0, "g_to_k", key->params.elgamal.g_to_k);
+ print_bn(0, "encrypted_m", key->params.elgamal.encrypted_m);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "print_pk_sesskey: unusual algorithm\n");
+ }
+ if (tag == PGP_PTAG_CT_PK_SESSION_KEY) {
+ printf("Symmetric algorithm: %d (%s)\n", key->symm_alg,
+ pgp_show_symm_alg(key->symm_alg));
+ print_hexdump(0, "Key", key->key, pgp_key_size(key->symm_alg));
+ printf("Checksum: %04x\n", key->checksum);
+ }
+}
+
+static void
+start_subpacket(int *indent, int type)
+{
+ *indent += 1;
+ print_indent(*indent);
+ printf("-- %s (type 0x%02x)\n",
+ pgp_show_ss_type((pgp_content_enum)type),
+ type - PGP_PTAG_SIG_SUBPKT_BASE);
+}
+
+static void
+end_subpacket(int *indent)
+{
+ *indent -= 1;
+}
+
+/**
+\ingroup Core_Print
+\param contents
+*/
+int
+pgp_print_packet(pgp_printstate_t *print, const pgp_packet_t *pkt)
+{
+ const pgp_contents_t *content = &pkt->u;
+ pgp_text_t *text;
+ const char *str;
+
+ if (print->unarmoured && pkt->tag != PGP_PTAG_CT_UNARMOURED_TEXT) {
+ print->unarmoured = 0;
+ puts("UNARMOURED TEXT ends");
+ }
+ if (pkt->tag == PGP_PARSER_PTAG) {
+ printf("=> PGP_PARSER_PTAG: %s\n",
+ pgp_show_packet_tag((pgp_content_enum)content->ptag.type));
+ } else {
+ printf("=> %s\n", pgp_show_packet_tag(pkt->tag));
+ }
+
+ switch (pkt->tag) {
+ case PGP_PARSER_ERROR:
+ printf("parse error: %s\n", content->error);
+ break;
+
+ case PGP_PARSER_ERRCODE:
+ printf("parse error: %s\n",
+ pgp_errcode(content->errcode.errcode));
+ break;
+
+ case PGP_PARSER_PACKET_END:
+ print_packet_hex(&content->packet);
+ break;
+
+ case PGP_PARSER_PTAG:
+ if (content->ptag.type == PGP_PTAG_CT_PUBLIC_KEY) {
+ print->indent = 0;
+ printf("\n*** NEXT KEY ***\n");
+ }
+ printf("\n");
+ print_indent(print->indent);
+ printf("==== ptag new_format=%u type=%u length_type=%d"
+ " length=0x%x (%u) position=0x%x (%u)\n",
+ content->ptag.new_format,
+ content->ptag.type, content->ptag.length_type,
+ content->ptag.length, content->ptag.length,
+ content->ptag.position, content->ptag.position);
+ print_tagname(print->indent, pgp_show_packet_tag((pgp_content_enum)content->ptag.type));
+ break;
+
+ case PGP_PTAG_CT_SE_DATA_HEADER:
+ print_tagname(print->indent, "SYMMETRIC ENCRYPTED DATA");
+ break;
+
+ case PGP_PTAG_CT_SE_IP_DATA_HEADER:
+ print_tagname(print->indent,
+ "SYMMETRIC ENCRYPTED INTEGRITY PROTECTED DATA HEADER");
+ printf("Version: %d\n", content->se_ip_data_header);
+ break;
+
+ case PGP_PTAG_CT_SE_IP_DATA_BODY:
+ print_tagname(print->indent,
+ "SYMMETRIC ENCRYPTED INTEGRITY PROTECTED DATA BODY");
+ hexdump(stdout, "data", content->se_data_body.data,
+ content->se_data_body.length);
+ break;
+
+ case PGP_PTAG_CT_PUBLIC_KEY:
+ case PGP_PTAG_CT_PUBLIC_SUBKEY:
+ print_tagname(print->indent, (pkt->tag == PGP_PTAG_CT_PUBLIC_KEY) ?
+ "PUBLIC KEY" :
+ "PUBLIC SUBKEY");
+ pgp_print_pubkey(&content->pubkey);
+ break;
+
+ case PGP_PTAG_CT_TRUST:
+ print_tagname(print->indent, "TRUST");
+ print_data(print->indent, "Trust", &content->trust);
+ break;
+
+ case PGP_PTAG_CT_USER_ID:
+ print_tagname(print->indent, "USER ID");
+ print_utf8_string(print->indent, "userid", content->userid);
+ break;
+
+ case PGP_PTAG_CT_SIGNATURE:
+ print_tagname(print->indent, "SIGNATURE");
+ print_indent(print->indent);
+ print_uint(print->indent, "Signature Version",
+ (unsigned)content->sig.info.version);
+ if (content->sig.info.birthtime_set) {
+ print_time(print->indent, "Signature Creation Time",
+ content->sig.info.birthtime);
+ }
+ if (content->sig.info.duration_set) {
+ print_uint(print->indent, "Signature Duration",
+ (unsigned)content->sig.info.duration);
+ }
+
+ print_string_and_value(print->indent, "Signature Type",
+ pgp_show_sig_type(content->sig.info.type),
+ content->sig.info.type);
+
+ if (content->sig.info.signer_id_set) {
+ hexdump_data(print->indent, "Signer ID",
+ content->sig.info.signer_id,
+ (unsigned)sizeof(content->sig.info.signer_id));
+ }
+
+ print_string_and_value(print->indent, "Public Key Algorithm",
+ pgp_show_pka(content->sig.info.key_alg),
+ content->sig.info.key_alg);
+ print_string_and_value(print->indent, "Hash Algorithm",
+ pgp_show_hash_alg((uint8_t)
+ content->sig.info.hash_alg),
+ (uint8_t)content->sig.info.hash_alg);
+ print_uint(print->indent, "Hashed data len",
+ (unsigned)content->sig.info.v4_hashlen);
+ print_indent(print->indent);
+ hexdump_data(print->indent, "hash2", &content->sig.hash2[0], 2);
+ switch (content->sig.info.key_alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ print_bn(print->indent, "sig", content->sig.info.sig.rsa.sig);
+ break;
+
+ case PGP_PKA_DSA:
+ print_bn(print->indent, "r", content->sig.info.sig.dsa.r);
+ print_bn(print->indent, "s", content->sig.info.sig.dsa.s);
+ break;
+
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ print_bn(print->indent, "r", content->sig.info.sig.elgamal.r);
+ print_bn(print->indent, "s", content->sig.info.sig.elgamal.s);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_print_packet: Unusual algorithm\n");
+ return 0;
+ }
+
+ if (content->sig.hash)
+ printf("data hash is set\n");
+
+ break;
+
+ case PGP_PTAG_CT_COMPRESSED:
+ print_tagname(print->indent, "COMPRESSED");
+ print_uint(print->indent, "Compressed Data Type",
+ (unsigned)content->compressed);
+ break;
+
+ case PGP_PTAG_CT_1_PASS_SIG:
+ print_tagname(print->indent, "ONE PASS SIGNATURE");
+
+ print_uint(print->indent, "Version", (unsigned)content->one_pass_sig.version);
+ print_string_and_value(print->indent, "Signature Type",
+ pgp_show_sig_type(content->one_pass_sig.sig_type),
+ content->one_pass_sig.sig_type);
+ print_string_and_value(print->indent, "Hash Algorithm",
+ pgp_show_hash_alg((uint8_t)content->one_pass_sig.hash_alg),
+ (uint8_t)content->one_pass_sig.hash_alg);
+ print_string_and_value(print->indent, "Public Key Algorithm",
+ pgp_show_pka(content->one_pass_sig.key_alg),
+ content->one_pass_sig.key_alg);
+ hexdump_data(print->indent, "Signer ID",
+ content->one_pass_sig.keyid,
+ (unsigned)sizeof(content->one_pass_sig.keyid));
+ print_uint(print->indent, "Nested", content->one_pass_sig.nested);
+ break;
+
+ case PGP_PTAG_CT_USER_ATTR:
+ print_tagname(print->indent, "USER ATTRIBUTE");
+ print_hexdump(print->indent, "User Attribute",
+ content->userattr.contents,
+ (unsigned)content->userattr.len);
+ break;
+
+ case PGP_PTAG_RAW_SS:
+ if (pkt->critical) {
+ (void) fprintf(stderr, "contents are critical\n");
+ return 0;
+ }
+ start_subpacket(&print->indent, pkt->tag);
+ print_uint(print->indent, "Raw Signature Subpacket: tag",
+ (unsigned)(content->ss_raw.tag -
+ (unsigned)PGP_PTAG_SIG_SUBPKT_BASE));
+ print_hexdump(print->indent, "Raw Data",
+ content->ss_raw.raw,
+ (unsigned)content->ss_raw.length);
+ break;
+
+ case PGP_PTAG_SS_CREATION_TIME:
+ start_subpacket(&print->indent, pkt->tag);
+ print_time(print->indent, "Signature Creation Time", content->ss_time);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_EXPIRATION_TIME:
+ start_subpacket(&print->indent, pkt->tag);
+ print_duration(print->indent, "Signature Expiration Time",
+ content->ss_time);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_KEY_EXPIRY:
+ start_subpacket(&print->indent, pkt->tag);
+ print_duration(print->indent, "Key Expiration Time", content->ss_time);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_TRUST:
+ start_subpacket(&print->indent, pkt->tag);
+ print_string(print->indent, "Trust Signature", "");
+ print_uint(print->indent, "Level", (unsigned)content->ss_trust.level);
+ print_uint(print->indent, "Amount", (unsigned)content->ss_trust.amount);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_REVOCABLE:
+ start_subpacket(&print->indent, pkt->tag);
+ print_boolean(print->indent, "Revocable", content->ss_revocable);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_REVOCATION_KEY:
+ start_subpacket(&print->indent, pkt->tag);
+ /* not yet tested */
+ printf(" revocation key: class=0x%x",
+ content->ss_revocation_key.class);
+ if (content->ss_revocation_key.class & 0x40) {
+ printf(" (sensitive)");
+ }
+ printf(", algid=0x%x", content->ss_revocation_key.algid);
+ hexdump(stdout, "fingerprint", content->ss_revocation_key.fingerprint,
+ PGP_FINGERPRINT_SIZE);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_ISSUER_KEY_ID:
+ start_subpacket(&print->indent, pkt->tag);
+ print_hexdump(print->indent, "Issuer Key Id",
+ content->ss_issuer, (unsigned)sizeof(content->ss_issuer));
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_PREFERRED_SKA:
+ start_subpacket(&print->indent, pkt->tag);
+ print_data(print->indent, "Preferred Symmetric Algorithms",
+ &content->ss_skapref);
+ text = pgp_showall_ss_skapref(&content->ss_skapref);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_PRIMARY_USER_ID:
+ start_subpacket(&print->indent, pkt->tag);
+ print_boolean(print->indent, "Primary User ID",
+ content->ss_primary_userid);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_PREFERRED_HASH:
+ start_subpacket(&print->indent, pkt->tag);
+ print_data(print->indent, "Preferred Hash Algorithms",
+ &content->ss_hashpref);
+ text = pgp_showall_ss_hashpref(&content->ss_hashpref);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_PREF_COMPRESS:
+ start_subpacket(&print->indent, pkt->tag);
+ print_data(print->indent, "Preferred Compression Algorithms",
+ &content->ss_zpref);
+ text = pgp_showall_ss_zpref(&content->ss_zpref);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_KEY_FLAGS:
+ start_subpacket(&print->indent, pkt->tag);
+ print_data(print->indent, "Key Flags", &content->ss_key_flags);
+
+ text = pgp_showall_ss_key_flags(&content->ss_key_flags);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_KEYSERV_PREFS:
+ start_subpacket(&print->indent, pkt->tag);
+ print_data(print->indent, "Key Server Preferences",
+ &content->ss_key_server_prefs);
+ text = pgp_show_keyserv_prefs(&content->ss_key_server_prefs);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_FEATURES:
+ start_subpacket(&print->indent, pkt->tag);
+ print_data(print->indent, "Features", &content->ss_features);
+ text = pgp_showall_ss_features(content->ss_features);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_NOTATION_DATA:
+ start_subpacket(&print->indent, pkt->tag);
+ print_indent(print->indent);
+ printf("Notation Data:\n");
+
+ print->indent++;
+ print_data(print->indent, "Flags", &content->ss_notation.flags);
+ text = pgp_showall_notation(content->ss_notation);
+ print_text_breakdown(print->indent, text);
+ pgp_text_free(text);
+
+ print_data(print->indent, "Name", &content->ss_notation.name);
+
+ print_data(print->indent, "Value", &content->ss_notation.value);
+
+ print->indent--;
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_REGEXP:
+ start_subpacket(&print->indent, pkt->tag);
+ print_hexdump(print->indent, "Regular Expression",
+ (uint8_t *) content->ss_regexp,
+ (unsigned)strlen(content->ss_regexp));
+ print_string(print->indent, NULL, content->ss_regexp);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_POLICY_URI:
+ start_subpacket(&print->indent, pkt->tag);
+ print_string(print->indent, "Policy URL", content->ss_policy);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_SIGNERS_USER_ID:
+ start_subpacket(&print->indent, pkt->tag);
+ print_utf8_string(print->indent, "Signer's User ID", content->ss_signer);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_PREF_KEYSERV:
+ start_subpacket(&print->indent, pkt->tag);
+ print_string(print->indent, "Preferred Key Server", content->ss_keyserv);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_EMBEDDED_SIGNATURE:
+ start_subpacket(&print->indent, pkt->tag);
+ end_subpacket(&print->indent);/* \todo print out contents? */
+ break;
+
+ case PGP_PTAG_SS_USERDEFINED00:
+ case PGP_PTAG_SS_USERDEFINED01:
+ case PGP_PTAG_SS_USERDEFINED02:
+ case PGP_PTAG_SS_USERDEFINED03:
+ case PGP_PTAG_SS_USERDEFINED04:
+ case PGP_PTAG_SS_USERDEFINED05:
+ case PGP_PTAG_SS_USERDEFINED06:
+ case PGP_PTAG_SS_USERDEFINED07:
+ case PGP_PTAG_SS_USERDEFINED08:
+ case PGP_PTAG_SS_USERDEFINED09:
+ case PGP_PTAG_SS_USERDEFINED10:
+ start_subpacket(&print->indent, pkt->tag);
+ print_hexdump(print->indent, "Internal or user-defined",
+ content->ss_userdef.contents,
+ (unsigned)content->ss_userdef.len);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_RESERVED:
+ start_subpacket(&print->indent, pkt->tag);
+ print_hexdump(print->indent, "Reserved",
+ content->ss_userdef.contents,
+ (unsigned)content->ss_userdef.len);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_SS_REVOCATION_REASON:
+ start_subpacket(&print->indent, pkt->tag);
+ print_hexdump(print->indent, "Revocation Reason",
+ &content->ss_revocation.code,
+ 1);
+ str = pgp_show_ss_rr_code(content->ss_revocation.code);
+ print_string(print->indent, NULL, str);
+ end_subpacket(&print->indent);
+ break;
+
+ case PGP_PTAG_CT_LITDATA_HEADER:
+ print_tagname(print->indent, "LITERAL DATA HEADER");
+ printf(" literal data header format=%c filename='%s'\n",
+ content->litdata_header.format,
+ content->litdata_header.filename);
+ showtime(" modification time",
+ content->litdata_header.mtime);
+ printf("\n");
+ break;
+
+ case PGP_PTAG_CT_LITDATA_BODY:
+ print_tagname(print->indent, "LITERAL DATA BODY");
+ printf(" literal data body length=%u\n",
+ content->litdata_body.length);
+ printf(" data=");
+ print_escaped(content->litdata_body.data,
+ content->litdata_body.length);
+ printf("\n");
+ break;
+
+ case PGP_PTAG_CT_SIGNATURE_HEADER:
+ print_tagname(print->indent, "SIGNATURE");
+ print_indent(print->indent);
+ print_uint(print->indent, "Signature Version",
+ (unsigned)content->sig.info.version);
+ if (content->sig.info.birthtime_set) {
+ print_time(print->indent, "Signature Creation Time",
+ content->sig.info.birthtime);
+ }
+ if (content->sig.info.duration_set) {
+ print_uint(print->indent, "Signature Duration",
+ (unsigned)content->sig.info.duration);
+ }
+ print_string_and_value(print->indent, "Signature Type",
+ pgp_show_sig_type(content->sig.info.type),
+ content->sig.info.type);
+ if (content->sig.info.signer_id_set) {
+ hexdump_data(print->indent, "Signer ID",
+ content->sig.info.signer_id,
+ (unsigned)sizeof(content->sig.info.signer_id));
+ }
+ print_string_and_value(print->indent, "Public Key Algorithm",
+ pgp_show_pka(content->sig.info.key_alg),
+ content->sig.info.key_alg);
+ print_string_and_value(print->indent, "Hash Algorithm",
+ pgp_show_hash_alg((uint8_t)content->sig.info.hash_alg),
+ (uint8_t)content->sig.info.hash_alg);
+ print_uint(print->indent, "Hashed data len",
+ (unsigned)content->sig.info.v4_hashlen);
+
+ break;
+
+ case PGP_PTAG_CT_SIGNATURE_FOOTER:
+ print_indent(print->indent);
+ hexdump_data(print->indent, "hash2", &content->sig.hash2[0], 2);
+
+ switch (content->sig.info.key_alg) {
+ case PGP_PKA_RSA:
+ print_bn(print->indent, "sig", content->sig.info.sig.rsa.sig);
+ break;
+
+ case PGP_PKA_DSA:
+ print_bn(print->indent, "r", content->sig.info.sig.dsa.r);
+ print_bn(print->indent, "s", content->sig.info.sig.dsa.s);
+ break;
+
+ case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
+ print_bn(print->indent, "r", content->sig.info.sig.elgamal.r);
+ print_bn(print->indent, "s", content->sig.info.sig.elgamal.s);
+ break;
+
+ case PGP_PKA_PRIVATE00:
+ case PGP_PKA_PRIVATE01:
+ case PGP_PKA_PRIVATE02:
+ case PGP_PKA_PRIVATE03:
+ case PGP_PKA_PRIVATE04:
+ case PGP_PKA_PRIVATE05:
+ case PGP_PKA_PRIVATE06:
+ case PGP_PKA_PRIVATE07:
+ case PGP_PKA_PRIVATE08:
+ case PGP_PKA_PRIVATE09:
+ case PGP_PKA_PRIVATE10:
+ print_data(print->indent, "Private/Experimental",
+ &content->sig.info.sig.unknown);
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "pgp_print_packet: Unusual key algorithm\n");
+ return 0;
+ }
+ break;
+
+ case PGP_GET_PASSPHRASE:
+ print_tagname(print->indent, "PGP_GET_PASSPHRASE");
+ break;
+
+ case PGP_PTAG_CT_SECRET_KEY:
+ print_tagname(print->indent, "PGP_PTAG_CT_SECRET_KEY");
+ print_seckey_verbose(pkt->tag, &content->seckey);
+ break;
+
+ case PGP_PTAG_CT_ENCRYPTED_SECRET_KEY:
+ print_tagname(print->indent, "PGP_PTAG_CT_ENCRYPTED_SECRET_KEY");
+ print_seckey_verbose(pkt->tag, &content->seckey);
+ break;
+
+ case PGP_PTAG_CT_ARMOUR_HEADER:
+ print_tagname(print->indent, "ARMOUR HEADER");
+ print_string(print->indent, "type", content->armour_header.type);
+ break;
+
+ case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
+ print_tagname(print->indent, "SIGNED CLEARTEXT HEADER");
+ print_headers(&content->cleartext_head);
+ break;
+
+ case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
+ print_tagname(print->indent, "SIGNED CLEARTEXT BODY");
+ print_block(print->indent, "signed cleartext", content->cleartext_body.data,
+ content->cleartext_body.length);
+ break;
+
+ case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
+ print_tagname(print->indent, "SIGNED CLEARTEXT TRAILER");
+ printf("hash algorithm: %d\n",
+ content->cleartext_trailer->alg);
+ printf("\n");
+ break;
+
+ case PGP_PTAG_CT_UNARMOURED_TEXT:
+ if (!print->unarmoured) {
+ print_tagname(print->indent, "UNARMOURED TEXT");
+ print->unarmoured = 1;
+ }
+ putchar('[');
+ print_escaped(content->unarmoured_text.data,
+ content->unarmoured_text.length);
+ putchar(']');
+ break;
+
+ case PGP_PTAG_CT_ARMOUR_TRAILER:
+ print_tagname(print->indent, "ARMOUR TRAILER");
+ print_string(print->indent, "type", content->armour_header.type);
+ break;
+
+ case PGP_PTAG_CT_PK_SESSION_KEY:
+ case PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
+ print_pk_sesskey(pkt->tag, &content->pk_sesskey);
+ break;
+
+ case PGP_GET_SECKEY:
+ print_pk_sesskey(PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY,
+ content->get_seckey.pk_sesskey);
+ break;
+
+ default:
+ print_tagname(print->indent, "UNKNOWN PACKET TYPE");
+ fprintf(stderr, "pgp_print_packet: unknown tag=%d (0x%x)\n",
+ pkt->tag, pkt->tag);
+ return 0;
+ }
+ return 1;
+}
+
+static pgp_cb_ret_t
+cb_list_packets(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ pgp_print_packet(&cbinfo->printstate, pkt);
+ return PGP_RELEASE_MEMORY;
+}
+
+/**
+\ingroup Core_Print
+\param filename
+\param armour
+\param keyring
+\param cb_get_passphrase
+*/
+int
+pgp_list_packets(pgp_io_t *io,
+ char *filename,
+ unsigned armour,
+ pgp_keyring_t *secring,
+ pgp_keyring_t *pubring,
+ void *passfp,
+ pgp_cbfunc_t *cb_get_passphrase)
+{
+ pgp_stream_t *stream = NULL;
+ const unsigned accumulate = 1;
+ const int printerrors = 1;
+ int fd;
+
+ fd = pgp_setup_file_read(io, &stream, filename, NULL, cb_list_packets,
+ accumulate);
+ pgp_parse_options(stream, PGP_PTAG_SS_ALL, PGP_PARSE_PARSED);
+ stream->cryptinfo.secring = secring;
+ stream->cryptinfo.pubring = pubring;
+ stream->cbinfo.passfp = passfp;
+ stream->cryptinfo.getpassphrase = cb_get_passphrase;
+ if (armour) {
+ pgp_reader_push_dearmour(stream);
+ }
+ pgp_parse(stream, printerrors);
+ pgp_teardown_file_read(stream, fd);
+ return 1;
+}
diff --git a/libs/netpgp/src/lib/packet-show.c b/libs/netpgp/src/lib/packet-show.c
new file mode 100644
index 00000000..ac150936
--- /dev/null
+++ b/libs/netpgp/src/lib/packet-show.c
@@ -0,0 +1,914 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ *
+ * Creates printable text strings from packet contents
+ *
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: packet-show.c,v 1.21 2011/08/14 11:19:51 christos Exp $");
+#endif
+
+#include
+#include
+
+#include "packet-show.h"
+
+#include "netpgpsdk.h"
+#include "netpgpdefs.h"
+
+
+/*
+ * Arrays of value->text maps
+ */
+
+static pgp_map_t packet_tag_map[] =
+{
+ {PGP_PTAG_CT_RESERVED, "Reserved"},
+ {PGP_PTAG_CT_PK_SESSION_KEY, "Public-Key Encrypted Session Key"},
+ {PGP_PTAG_CT_SIGNATURE, "Signature"},
+ {PGP_PTAG_CT_SK_SESSION_KEY, "Symmetric-Key Encrypted Session Key"},
+ {PGP_PTAG_CT_1_PASS_SIG, "One-Pass Signature"},
+ {PGP_PTAG_CT_SECRET_KEY, "Secret Key"},
+ {PGP_PTAG_CT_PUBLIC_KEY, "Public Key"},
+ {PGP_PTAG_CT_SECRET_SUBKEY, "Secret Subkey"},
+ {PGP_PTAG_CT_COMPRESSED, "Compressed Data"},
+ {PGP_PTAG_CT_SE_DATA, "Symmetrically Encrypted Data"},
+ {PGP_PTAG_CT_MARKER, "Marker"},
+ {PGP_PTAG_CT_LITDATA, "Literal Data"},
+ {PGP_PTAG_CT_TRUST, "Trust"},
+ {PGP_PTAG_CT_USER_ID, "User ID"},
+ {PGP_PTAG_CT_PUBLIC_SUBKEY, "Public Subkey"},
+ {PGP_PTAG_CT_RESERVED2, "reserved2"},
+ {PGP_PTAG_CT_RESERVED3, "reserved3"},
+ {PGP_PTAG_CT_USER_ATTR, "User Attribute"},
+ {PGP_PTAG_CT_SE_IP_DATA,
+ "Symmetric Encrypted and Integrity Protected Data"},
+ {PGP_PTAG_CT_MDC, "Modification Detection Code"},
+ {PGP_PARSER_PTAG, "PGP_PARSER_PTAG"},
+ {PGP_PTAG_RAW_SS, "PGP_PTAG_RAW_SS"},
+ {PGP_PTAG_SS_ALL, "PGP_PTAG_SS_ALL"},
+ {PGP_PARSER_PACKET_END, "PGP_PARSER_PACKET_END"},
+ {PGP_PTAG_SIG_SUBPKT_BASE, "PGP_PTAG_SIG_SUBPKT_BASE"},
+ {PGP_PTAG_SS_CREATION_TIME, "SS: Signature Creation Time"},
+ {PGP_PTAG_SS_EXPIRATION_TIME, "SS: Signature Expiration Time"},
+ {PGP_PTAG_SS_EXPORT_CERT, "SS: Exportable Certification"},
+ {PGP_PTAG_SS_TRUST, "SS: Trust Signature"},
+ {PGP_PTAG_SS_REGEXP, "SS: Regular Expression"},
+ {PGP_PTAG_SS_REVOCABLE, "SS: Revocable"},
+ {PGP_PTAG_SS_KEY_EXPIRY, "SS: Key Expiration Time"},
+ {PGP_PTAG_SS_RESERVED, "SS: Reserved"},
+ {PGP_PTAG_SS_PREFERRED_SKA, "SS: Preferred Secret Key Algorithm"},
+ {PGP_PTAG_SS_REVOCATION_KEY, "SS: Revocation Key"},
+ {PGP_PTAG_SS_ISSUER_KEY_ID, "SS: Issuer Key Id"},
+ {PGP_PTAG_SS_NOTATION_DATA, "SS: Notation Data"},
+ {PGP_PTAG_SS_PREFERRED_HASH, "SS: Preferred Hash Algorithm"},
+ {PGP_PTAG_SS_PREF_COMPRESS, "SS: Preferred Compression Algorithm"},
+ {PGP_PTAG_SS_KEYSERV_PREFS, "SS: Key Server Preferences"},
+ {PGP_PTAG_SS_PREF_KEYSERV, "SS: Preferred Key Server"},
+ {PGP_PTAG_SS_PRIMARY_USER_ID, "SS: Primary User ID"},
+ {PGP_PTAG_SS_POLICY_URI, "SS: Policy URI"},
+ {PGP_PTAG_SS_KEY_FLAGS, "SS: Key Flags"},
+ {PGP_PTAG_SS_SIGNERS_USER_ID, "SS: Signer's User ID"},
+ {PGP_PTAG_SS_REVOCATION_REASON, "SS: Reason for Revocation"},
+ {PGP_PTAG_SS_FEATURES, "SS: Features"},
+ {PGP_PTAG_SS_SIGNATURE_TARGET, "SS: Signature Target"},
+ {PGP_PTAG_SS_EMBEDDED_SIGNATURE, "SS: Embedded Signature"},
+
+ {PGP_PTAG_CT_LITDATA_HEADER, "CT: Literal Data Header"},
+ {PGP_PTAG_CT_LITDATA_BODY, "CT: Literal Data Body"},
+ {PGP_PTAG_CT_SIGNATURE_HEADER, "CT: Signature Header"},
+ {PGP_PTAG_CT_SIGNATURE_FOOTER, "CT: Signature Footer"},
+ {PGP_PTAG_CT_ARMOUR_HEADER, "CT: Armour Header"},
+ {PGP_PTAG_CT_ARMOUR_TRAILER, "CT: Armour Trailer"},
+ {PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER, "CT: Signed Cleartext Header"},
+ {PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY, "CT: Signed Cleartext Body"},
+ {PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER, "CT: Signed Cleartext Trailer"},
+ {PGP_PTAG_CT_UNARMOURED_TEXT, "CT: Unarmoured Text"},
+ {PGP_PTAG_CT_ENCRYPTED_SECRET_KEY, "CT: Encrypted Secret Key"},
+ {PGP_PTAG_CT_SE_DATA_HEADER, "CT: Sym Encrypted Data Header"},
+ {PGP_PTAG_CT_SE_DATA_BODY, "CT: Sym Encrypted Data Body"},
+ {PGP_PTAG_CT_SE_IP_DATA_HEADER, "CT: Sym Encrypted IP Data Header"},
+ {PGP_PTAG_CT_SE_IP_DATA_BODY, "CT: Sym Encrypted IP Data Body"},
+ {PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY, "CT: Encrypted PK Session Key"},
+ {PGP_GET_PASSPHRASE, "CMD: Get Secret Key Passphrase"},
+ {PGP_GET_SECKEY, "CMD: Get Secret Key"},
+ {PGP_PARSER_ERROR, "PGP_PARSER_ERROR"},
+ {PGP_PARSER_ERRCODE, "PGP_PARSER_ERRCODE"},
+
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_map_t ss_type_map[] =
+{
+ {PGP_PTAG_SS_CREATION_TIME, "Signature Creation Time"},
+ {PGP_PTAG_SS_EXPIRATION_TIME, "Signature Expiration Time"},
+ {PGP_PTAG_SS_TRUST, "Trust Signature"},
+ {PGP_PTAG_SS_REGEXP, "Regular Expression"},
+ {PGP_PTAG_SS_REVOCABLE, "Revocable"},
+ {PGP_PTAG_SS_KEY_EXPIRY, "Key Expiration Time"},
+ {PGP_PTAG_SS_PREFERRED_SKA, "Preferred Symmetric Algorithms"},
+ {PGP_PTAG_SS_REVOCATION_KEY, "Revocation Key"},
+ {PGP_PTAG_SS_ISSUER_KEY_ID, "Issuer key ID"},
+ {PGP_PTAG_SS_NOTATION_DATA, "Notation Data"},
+ {PGP_PTAG_SS_PREFERRED_HASH, "Preferred Hash Algorithms"},
+ {PGP_PTAG_SS_PREF_COMPRESS, "Preferred Compression Algorithms"},
+ {PGP_PTAG_SS_KEYSERV_PREFS, "Key Server Preferences"},
+ {PGP_PTAG_SS_PREF_KEYSERV, "Preferred Key Server"},
+ {PGP_PTAG_SS_PRIMARY_USER_ID, "Primary User ID"},
+ {PGP_PTAG_SS_POLICY_URI, "Policy URI"},
+ {PGP_PTAG_SS_KEY_FLAGS, "Key Flags"},
+ {PGP_PTAG_SS_REVOCATION_REASON, "Reason for Revocation"},
+ {PGP_PTAG_SS_FEATURES, "Features"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+
+static pgp_map_t ss_rr_code_map[] =
+{
+ {0x00, "No reason specified"},
+ {0x01, "Key is superseded"},
+ {0x02, "Key material has been compromised"},
+ {0x03, "Key is retired and no longer used"},
+ {0x20, "User ID information is no longer valid"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_map_t sig_type_map[] =
+{
+ {PGP_SIG_BINARY, "Signature of a binary document"},
+ {PGP_SIG_TEXT, "Signature of a canonical text document"},
+ {PGP_SIG_STANDALONE, "Standalone signature"},
+ {PGP_CERT_GENERIC, "Generic certification of a User ID and Public Key packet"},
+ {PGP_CERT_PERSONA, "Personal certification of a User ID and Public Key packet"},
+ {PGP_CERT_CASUAL, "Casual certification of a User ID and Public Key packet"},
+ {PGP_CERT_POSITIVE, "Positive certification of a User ID and Public Key packet"},
+ {PGP_SIG_SUBKEY, "Subkey Binding Signature"},
+ {PGP_SIG_PRIMARY, "Primary Key Binding Signature"},
+ {PGP_SIG_DIRECT, "Signature directly on a key"},
+ {PGP_SIG_REV_KEY, "Key revocation signature"},
+ {PGP_SIG_REV_SUBKEY, "Subkey revocation signature"},
+ {PGP_SIG_REV_CERT, "Certification revocation signature"},
+ {PGP_SIG_TIMESTAMP, "Timestamp signature"},
+ {PGP_SIG_3RD_PARTY, "Third-Party Confirmation signature"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_map_t pubkey_alg_map[] =
+{
+ {PGP_PKA_RSA, "RSA (Encrypt or Sign)"},
+ {PGP_PKA_RSA_ENCRYPT_ONLY, "RSA Encrypt-Only"},
+ {PGP_PKA_RSA_SIGN_ONLY, "RSA Sign-Only"},
+ {PGP_PKA_ELGAMAL, "Elgamal (Encrypt-Only)"},
+ {PGP_PKA_DSA, "DSA"},
+ {PGP_PKA_RESERVED_ELLIPTIC_CURVE, "Reserved for Elliptic Curve"},
+ {PGP_PKA_RESERVED_ECDSA, "Reserved for ECDSA"},
+ {PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN, "Reserved (formerly Elgamal Encrypt or Sign"},
+ {PGP_PKA_RESERVED_DH, "Reserved for Diffie-Hellman (X9.42)"},
+ {PGP_PKA_PRIVATE00, "Private/Experimental"},
+ {PGP_PKA_PRIVATE01, "Private/Experimental"},
+ {PGP_PKA_PRIVATE02, "Private/Experimental"},
+ {PGP_PKA_PRIVATE03, "Private/Experimental"},
+ {PGP_PKA_PRIVATE04, "Private/Experimental"},
+ {PGP_PKA_PRIVATE05, "Private/Experimental"},
+ {PGP_PKA_PRIVATE06, "Private/Experimental"},
+ {PGP_PKA_PRIVATE07, "Private/Experimental"},
+ {PGP_PKA_PRIVATE08, "Private/Experimental"},
+ {PGP_PKA_PRIVATE09, "Private/Experimental"},
+ {PGP_PKA_PRIVATE10, "Private/Experimental"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_map_t symm_alg_map[] =
+{
+ {PGP_SA_PLAINTEXT, "Plaintext or unencrypted data"},
+ {PGP_SA_IDEA, "IDEA"},
+ {PGP_SA_TRIPLEDES, "TripleDES"},
+ {PGP_SA_CAST5, "CAST5"},
+ {PGP_SA_BLOWFISH, "Blowfish"},
+ {PGP_SA_AES_128, "AES (128-bit key)"},
+ {PGP_SA_AES_192, "AES (192-bit key)"},
+ {PGP_SA_AES_256, "AES (256-bit key)"},
+ {PGP_SA_TWOFISH, "Twofish(256-bit key)"},
+ {PGP_SA_CAMELLIA_128, "Camellia (128-bit key)"},
+ {PGP_SA_CAMELLIA_192, "Camellia (192-bit key)"},
+ {PGP_SA_CAMELLIA_256, "Camellia (256-bit key)"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_map_t hash_alg_map[] =
+{
+ {PGP_HASH_MD5, "MD5"},
+ {PGP_HASH_SHA1, "SHA1"},
+ {PGP_HASH_RIPEMD, "RIPEMD160"},
+ {PGP_HASH_SHA256, "SHA256"},
+ {PGP_HASH_SHA384, "SHA384"},
+ {PGP_HASH_SHA512, "SHA512"},
+ {PGP_HASH_SHA224, "SHA224"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_map_t compression_alg_map[] =
+{
+ {PGP_C_NONE, "Uncompressed"},
+ {PGP_C_ZIP, "ZIP(RFC1951)"},
+ {PGP_C_ZLIB, "ZLIB(RFC1950)"},
+ {PGP_C_BZIP2, "Bzip2(BZ2)"},
+ {0x00, NULL}, /* this is the end-of-array marker */
+};
+
+static pgp_bit_map_t ss_notation_map_byte0[] =
+{
+ {0x80, "Human-readable"},
+ {0x00, NULL},
+};
+
+static pgp_bit_map_t *ss_notation_map[] =
+{
+ ss_notation_map_byte0,
+};
+
+static pgp_bit_map_t ss_feature_map_byte0[] =
+{
+ {0x01, "Modification Detection"},
+ {0x00, NULL},
+};
+
+static pgp_bit_map_t *ss_feature_map[] =
+{
+ ss_feature_map_byte0,
+};
+
+static pgp_bit_map_t ss_key_flags_map[] =
+{
+ {0x01, "May be used to certify other keys"},
+ {0x02, "May be used to sign data"},
+ {0x04, "May be used to encrypt communications"},
+ {0x08, "May be used to encrypt storage"},
+ {0x10, "Private component may have been split by a secret-sharing mechanism"},
+ {0x80, "Private component may be in possession of more than one person"},
+ {0x00, NULL},
+};
+
+static pgp_bit_map_t ss_key_server_prefs_map[] =
+{
+ {0x80, "Key holder requests that this key only be modified or updated by the key holder or an administrator of the key server"},
+ {0x00, NULL},
+};
+
+/*
+ * Private functions
+ */
+
+static void
+list_init(pgp_list_t *list)
+{
+ list->size = 0;
+ list->used = 0;
+ list->strings = NULL;
+}
+
+static void
+list_free_strings(pgp_list_t *list)
+{
+ unsigned i;
+
+ for (i = 0; i < list->used; i++) {
+ free(list->strings[i]);
+ list->strings[i] = NULL;
+ }
+}
+
+static void
+list_free(pgp_list_t *list)
+{
+ if (list->strings)
+ free(list->strings);
+ list_init(list);
+}
+
+static unsigned
+list_resize(pgp_list_t *list)
+{
+ /*
+ * We only resize in one direction - upwards. Algorithm used : double
+ * the current size then add 1
+ */
+ char **newstrings;
+ int newsize;
+
+ newsize = (list->size * 2) + 1;
+ newstrings = realloc(list->strings, newsize * sizeof(char *));
+ if (newstrings) {
+ list->strings = newstrings;
+ list->size = newsize;
+ return 1;
+ }
+ (void) fprintf(stderr, "list_resize - bad alloc\n");
+ return 0;
+}
+
+static unsigned
+add_str(pgp_list_t *list, const char *str)
+{
+ if (list->size == list->used && !list_resize(list)) {
+ return 0;
+ }
+ list->strings[list->used++] = __UNCONST(str);
+ return 1;
+}
+
+/* find a bitfield in a map - serial search */
+static const char *
+find_bitfield(pgp_bit_map_t *map, uint8_t octet)
+{
+ pgp_bit_map_t *row;
+
+ for (row = map; row->string != NULL && row->mask != octet ; row++) {
+ }
+ return (row->string) ? row->string : "Unknown";
+}
+
+/* ! generic function to initialise pgp_text_t structure */
+void
+pgp_text_init(pgp_text_t *text)
+{
+ list_init(&text->known);
+ list_init(&text->unknown);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * pgp_text_free() frees the memory used by an pgp_text_t structure
+ *
+ * \param text Pointer to a previously allocated structure. This structure and its contents will be freed.
+ */
+void
+pgp_text_free(pgp_text_t *text)
+{
+ /* Strings in "known" array will be constants, so don't free them */
+ list_free(&text->known);
+
+ /*
+ * Strings in "unknown" array will be dynamically allocated, so do
+ * free them
+ */
+ list_free_strings(&text->unknown);
+ list_free(&text->unknown);
+
+ free(text);
+}
+
+/* XXX: should this (and many others) be unsigned? */
+/* ! generic function which adds text derived from single octet map to text */
+static unsigned
+add_str_from_octet_map(pgp_text_t *map, char *str, uint8_t octet)
+{
+ if (str && !add_str(&map->known, str)) {
+ /*
+ * value recognised, but there was a problem adding it to the
+ * list
+ */
+ /* XXX - should print out error msg here, Ben? - rachel */
+ return 0;
+ } else if (!str) {
+ /*
+ * value not recognised and there was a problem adding it to
+ * the unknown list
+ */
+ unsigned len = 2 + 2 + 1; /* 2 for "0x", 2 for
+ * single octet in hex
+ * format, 1 for NUL */
+ if ((str = calloc(1, len)) == NULL) {
+ (void) fprintf(stderr, "add_str_from_octet_map: bad alloc\n");
+ return 0;
+ }
+ (void) snprintf(str, len, "0x%x", octet);
+ if (!add_str(&map->unknown, str)) {
+ return 0;
+ }
+ free(str);
+ }
+ return 1;
+}
+
+/* ! generic function which adds text derived from single bit map to text */
+static unsigned
+add_bitmap_entry(pgp_text_t *map, const char *str, uint8_t bit)
+{
+
+ if (str && !add_str(&map->known, str)) {
+ /*
+ * value recognised, but there was a problem adding it to the
+ * list
+ */
+ /* XXX - should print out error msg here, Ben? - rachel */
+ return 0;
+ } else if (!str) {
+ /*
+ * value not recognised and there was a problem adding it to
+ * the unknown list
+ * 2 chars of the string are the format definition, this will
+ * be replaced in the output by 2 chars of hex, so the length
+ * will be correct
+ */
+ char *newstr;
+ if (pgp_asprintf(&newstr, "Unknown bit(0x%x)", bit) == -1) {
+ (void) fprintf(stderr, "add_bitmap_entry: bad alloc\n");
+ return 0;
+ }
+ if (!add_str(&map->unknown, newstr)) {
+ return 0;
+ }
+ free(newstr);
+ }
+ return 1;
+}
+
+/**
+ * Produce a structure containing human-readable textstrings
+ * representing the recognised and unrecognised contents
+ * of this byte array. text_fn() will be called on each octet in turn.
+ * Each octet will generate one string representing the whole byte.
+ *
+ */
+
+static pgp_text_t *
+text_from_bytemapped_octets(const pgp_data_t *data,
+ const char *(*text_fn)(uint8_t octet))
+{
+ pgp_text_t *text;
+ const char *str;
+ unsigned i;
+
+ /*
+ * ! allocate and initialise pgp_text_t structure to store derived
+ * strings
+ */
+ if ((text = calloc(1, sizeof(*text))) == NULL) {
+ return NULL;
+ }
+
+ pgp_text_init(text);
+
+ /* ! for each octet in field ... */
+ for (i = 0; i < data->len; i++) {
+ /* ! derive string from octet */
+ str = (*text_fn) (data->contents[i]);
+
+ /* ! and add to text */
+ if (!add_str_from_octet_map(text, netpgp_strdup(str),
+ data->contents[i])) {
+ pgp_text_free(text);
+ return NULL;
+ }
+ }
+ /*
+ * ! All values have been added to either the known or the unknown
+ * list
+ */
+ return text;
+}
+
+/**
+ * Produce a structure containing human-readable textstrings
+ * representing the recognised and unrecognised contents
+ * of this byte array, derived from each bit of each octet.
+ *
+ */
+static pgp_text_t *
+showall_octets_bits(pgp_data_t *data, pgp_bit_map_t **map, size_t nmap)
+{
+ pgp_text_t *text;
+ const char *str;
+ unsigned i;
+ uint8_t mask, bit;
+ int j = 0;
+
+ /*
+ * ! allocate and initialise pgp_text_t structure to store derived
+ * strings
+ */
+ if ((text = calloc(1, sizeof(pgp_text_t))) == NULL) {
+ return NULL;
+ }
+
+ pgp_text_init(text);
+
+ /* ! for each octet in field ... */
+ for (i = 0; i < data->len; i++) {
+ /* ! for each bit in octet ... */
+ mask = 0x80;
+ for (j = 0; j < 8; j++, mask = (unsigned)mask >> 1) {
+ bit = data->contents[i] & mask;
+ if (bit) {
+ str = (i >= nmap) ? "Unknown" :
+ find_bitfield(map[i], bit);
+ if (!add_bitmap_entry(text, str, bit)) {
+ pgp_text_free(text);
+ return NULL;
+ }
+ }
+ }
+ }
+ return text;
+}
+
+/*
+ * Public Functions
+ */
+
+/**
+ * \ingroup Core_Print
+ * returns description of the Packet Tag
+ * \param packet_tag
+ * \return string or "Unknown"
+*/
+const char *
+pgp_show_packet_tag(pgp_content_enum packet_tag)
+{
+ const char *ret;
+
+ ret = pgp_str_from_map(packet_tag, packet_tag_map);
+ if (!ret) {
+ ret = "Unknown Tag";
+ }
+ return ret;
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns description of the Signature Sub-Packet type
+ * \param ss_type Signature Sub-Packet type
+ * \return string or "Unknown"
+ */
+const char *
+pgp_show_ss_type(pgp_content_enum ss_type)
+{
+ return pgp_str_from_map(ss_type, ss_type_map);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns description of the Revocation Reason code
+ * \param ss_rr_code Revocation Reason code
+ * \return string or "Unknown"
+ */
+const char *
+pgp_show_ss_rr_code(pgp_ss_rr_code_t ss_rr_code)
+{
+ return pgp_str_from_map(ss_rr_code, ss_rr_code_map);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns description of the given Signature type
+ * \param sig_type Signature type
+ * \return string or "Unknown"
+ */
+const char *
+pgp_show_sig_type(pgp_sig_type_t sig_type)
+{
+ return pgp_str_from_map(sig_type, sig_type_map);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns description of the given Public Key Algorithm
+ * \param pka Public Key Algorithm type
+ * \return string or "Unknown"
+ */
+const char *
+pgp_show_pka(pgp_pubkey_alg_t pka)
+{
+ return pgp_str_from_map(pka, pubkey_alg_map);
+}
+
+/**
+ * \ingroup Core_Print
+ * returns description of the Preferred Compression
+ * \param octet Preferred Compression
+ * \return string or "Unknown"
+*/
+const char *
+pgp_show_ss_zpref(uint8_t octet)
+{
+ return pgp_str_from_map(octet, compression_alg_map);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns set of descriptions of the given Preferred Compression Algorithms
+ * \param ss_zpref Array of Preferred Compression Algorithms
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ */
+pgp_text_t *
+pgp_showall_ss_zpref(const pgp_data_t *ss_zpref)
+{
+ return text_from_bytemapped_octets(ss_zpref,
+ &pgp_show_ss_zpref);
+}
+
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns description of the Hash Algorithm type
+ * \param hash Hash Algorithm type
+ * \return string or "Unknown"
+ */
+const char *
+pgp_show_hash_alg(uint8_t hash)
+{
+ return pgp_str_from_map(hash, hash_alg_map);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns set of descriptions of the given Preferred Hash Algorithms
+ * \param ss_hashpref Array of Preferred Hash Algorithms
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ */
+pgp_text_t *
+pgp_showall_ss_hashpref(const pgp_data_t *ss_hashpref)
+{
+ return text_from_bytemapped_octets(ss_hashpref,
+ &pgp_show_hash_alg);
+}
+
+const char *
+pgp_show_symm_alg(uint8_t hash)
+{
+ return pgp_str_from_map(hash, symm_alg_map);
+}
+
+/**
+ * \ingroup Core_Print
+ * returns description of the given Preferred Symmetric Key Algorithm
+ * \param octet
+ * \return string or "Unknown"
+*/
+const char *
+pgp_show_ss_skapref(uint8_t octet)
+{
+ return pgp_str_from_map(octet, symm_alg_map);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns set of descriptions of the given Preferred Symmetric Key Algorithms
+ * \param ss_skapref Array of Preferred Symmetric Key Algorithms
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ */
+pgp_text_t *
+pgp_showall_ss_skapref(const pgp_data_t *ss_skapref)
+{
+ return text_from_bytemapped_octets(ss_skapref,
+ &pgp_show_ss_skapref);
+}
+
+/**
+ * \ingroup Core_Print
+ * returns description of one SS Feature
+ * \param octet
+ * \return string or "Unknown"
+*/
+static const char *
+show_ss_feature(uint8_t octet, unsigned offset)
+{
+ if (offset >= PGP_ARRAY_SIZE(ss_feature_map)) {
+ return "Unknown";
+ }
+ return find_bitfield(ss_feature_map[offset], octet);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns set of descriptions of the given SS Features
+ * \param ss_features Signature Sub-Packet Features
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ */
+/* XXX: shouldn't this use show_all_octets_bits? */
+pgp_text_t *
+pgp_showall_ss_features(pgp_data_t ss_features)
+{
+ pgp_text_t *text;
+ const char *str;
+ unsigned i;
+ uint8_t mask, bit;
+ int j;
+
+ if ((text = calloc(1, sizeof(*text))) == NULL) {
+ return NULL;
+ }
+
+ pgp_text_init(text);
+
+ for (i = 0; i < ss_features.len; i++) {
+ mask = 0x80;
+ for (j = 0; j < 8; j++, mask = (unsigned)mask >> 1) {
+ bit = ss_features.contents[i] & mask;
+ if (bit) {
+ str = show_ss_feature(bit, i);
+ if (!add_bitmap_entry(text, str, bit)) {
+ pgp_text_free(text);
+ return NULL;
+ }
+ }
+ }
+ }
+ return text;
+}
+
+/**
+ * \ingroup Core_Print
+ * returns description of SS Key Flag
+ * \param octet
+ * \param map
+ * \return
+*/
+const char *
+pgp_show_ss_key_flag(uint8_t octet, pgp_bit_map_t *map)
+{
+ return find_bitfield(map, octet);
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns set of descriptions of the given Preferred Key Flags
+ * \param ss_key_flags Array of Key Flags
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ */
+pgp_text_t *
+pgp_showall_ss_key_flags(const pgp_data_t *ss_key_flags)
+{
+ pgp_text_t *text;
+ const char *str;
+ uint8_t mask, bit;
+ int i;
+
+ if ((text = calloc(1, sizeof(*text))) == NULL) {
+ return NULL;
+ }
+
+ pgp_text_init(text);
+
+ /* xxx - TBD: extend to handle multiple octets of bits - rachel */
+ for (i = 0, mask = 0x80; i < 8; i++, mask = (unsigned)mask >> 1) {
+ bit = ss_key_flags->contents[0] & mask;
+ if (bit) {
+ str = pgp_show_ss_key_flag(bit, ss_key_flags_map);
+ if (!add_bitmap_entry(text, netpgp_strdup(str), bit)) {
+ pgp_text_free(text);
+ return NULL;
+ }
+ }
+ }
+ /*
+ * xxx - must add error text if more than one octet. Only one
+ * currently specified -- rachel
+ */
+ return text;
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns description of one given Key Server Preference
+ *
+ * \param prefs Byte containing bitfield of preferences
+ * \param map
+ * \return string or "Unknown"
+ */
+const char *
+pgp_show_keyserv_pref(uint8_t prefs, pgp_bit_map_t *map)
+{
+ return find_bitfield(map, prefs);
+}
+
+/**
+ * \ingroup Core_Print
+ * returns set of descriptions of given Key Server Preferences
+ * \param ss_key_server_prefs
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ *
+*/
+pgp_text_t *
+pgp_show_keyserv_prefs(const pgp_data_t *prefs)
+{
+ pgp_text_t *text;
+ const char *str;
+ uint8_t mask, bit;
+ int i = 0;
+
+ if ((text = calloc(1, sizeof(*text))) == NULL) {
+ return NULL;
+ }
+
+ pgp_text_init(text);
+
+ /* xxx - TBD: extend to handle multiple octets of bits - rachel */
+
+ for (i = 0, mask = 0x80; i < 8; i++, mask = (unsigned)mask >> 1) {
+ bit = prefs->contents[0] & mask;
+ if (bit) {
+ str = pgp_show_keyserv_pref(bit,
+ ss_key_server_prefs_map);
+ if (!add_bitmap_entry(text, netpgp_strdup(str), bit)) {
+ pgp_text_free(text);
+ return NULL;
+ }
+ }
+ }
+ /*
+ * xxx - must add error text if more than one octet. Only one
+ * currently specified -- rachel
+ */
+ return text;
+}
+
+/**
+ * \ingroup Core_Print
+ *
+ * returns set of descriptions of the given SS Notation Data Flags
+ * \param ss_notation Signature Sub-Packet Notation Data
+ * \return NULL if cannot allocate memory or other error
+ * \return pointer to structure, if no error
+ */
+pgp_text_t *
+pgp_showall_notation(pgp_ss_notation_t ss_notation)
+{
+ return showall_octets_bits(&ss_notation.flags,
+ ss_notation_map,
+ PGP_ARRAY_SIZE(ss_notation_map));
+}
diff --git a/libs/netpgp/src/lib/packet-show.h b/libs/netpgp/src/lib/packet-show.h
new file mode 100644
index 00000000..1a4180c8
--- /dev/null
+++ b/libs/netpgp/src/lib/packet-show.h
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+
+#ifndef PACKET_SHOW_H_
+#define PACKET_SHOW_H_
+
+#include "packet.h"
+
+/** pgp_list_t
+ */
+typedef struct {
+ unsigned size; /* num of array slots allocated */
+ unsigned used; /* num of array slots currently used */
+ char **strings;
+} pgp_list_t;
+
+/** pgp_text_t
+ */
+typedef struct {
+ pgp_list_t known;
+ pgp_list_t unknown;
+} pgp_text_t;
+
+/** pgp_bit_map_t
+ */
+typedef struct {
+ uint8_t mask;
+ const char *string;
+} pgp_bit_map_t;
+
+void pgp_text_init(pgp_text_t *);
+void pgp_text_free(pgp_text_t *);
+
+const char *pgp_show_packet_tag(pgp_content_enum);
+const char *pgp_show_ss_type(pgp_content_enum);
+
+const char *pgp_show_sig_type(pgp_sig_type_t);
+const char *pgp_show_pka(pgp_pubkey_alg_t);
+
+pgp_text_t *pgp_showall_ss_zpref(const pgp_data_t *);
+const char *pgp_show_ss_zpref(uint8_t);
+
+pgp_text_t *pgp_showall_ss_hashpref(const pgp_data_t *);
+const char *pgp_show_hash_alg(uint8_t);
+const char *pgp_show_symm_alg(uint8_t);
+
+pgp_text_t *pgp_showall_ss_skapref(const pgp_data_t *);
+const char *pgp_show_ss_skapref(uint8_t);
+
+const char *pgp_show_ss_rr_code(pgp_ss_rr_code_t);
+
+pgp_text_t *pgp_showall_ss_features(pgp_data_t);
+
+pgp_text_t *pgp_showall_ss_key_flags(const pgp_data_t *);
+const char *pgp_show_ss_key_flag(uint8_t, pgp_bit_map_t *);
+
+pgp_text_t *pgp_show_keyserv_prefs(const pgp_data_t *);
+const char *pgp_show_keyserv_pref(uint8_t, pgp_bit_map_t *);
+
+pgp_text_t *pgp_showall_notation(pgp_ss_notation_t);
+
+#endif /* PACKET_SHOW_H_ */
diff --git a/libs/netpgp/src/lib/packet.h b/libs/netpgp/src/lib/packet.h
new file mode 100644
index 00000000..708286b3
--- /dev/null
+++ b/libs/netpgp/src/lib/packet.h
@@ -0,0 +1,972 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ * packet related headers.
+ */
+
+#ifndef PACKET_H_
+#define PACKET_H_
+
+#include
+
+#ifdef HAVE_OPENSSL_BN_H
+#include
+#endif
+
+#include "types.h"
+#include "errors.h"
+
+/* structure to keep track of printing state variables */
+typedef struct pgp_printstate_t {
+ unsigned unarmoured;
+ unsigned skipping;
+ int indent;
+} pgp_printstate_t;
+
+/** General-use structure for variable-length data
+ */
+
+typedef struct {
+ size_t len;
+ uint8_t *contents;
+ uint8_t mmapped; /* contents need an munmap(2) */
+} pgp_data_t;
+
+/************************************/
+/* Packet Tags - RFC4880, 4.2 */
+/************************************/
+
+/** Packet Tag - Bit 7 Mask (this bit is always set).
+ * The first byte of a packet is the "Packet Tag". It always
+ * has bit 7 set. This is the mask for it.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_ALWAYS_SET 0x80
+
+/** Packet Tag - New Format Flag.
+ * Bit 6 of the Packet Tag is the packet format indicator.
+ * If it is set, the new format is used, if cleared the
+ * old format is used.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_NEW_FORMAT 0x40
+
+
+/** Old Packet Format: Mask for content tag.
+ * In the old packet format bits 5 to 2 (including)
+ * are the content tag. This is the mask to apply
+ * to the packet tag. Note that you need to
+ * shift by #PGP_PTAG_OF_CONTENT_TAG_SHIFT bits.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_OF_CONTENT_TAG_MASK 0x3c
+/** Old Packet Format: Offset for the content tag.
+ * As described at #PGP_PTAG_OF_CONTENT_TAG_MASK the
+ * content tag needs to be shifted after being masked
+ * out from the Packet Tag.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_OF_CONTENT_TAG_SHIFT 2
+/** Old Packet Format: Mask for length type.
+ * Bits 1 and 0 of the packet tag are the length type
+ * in the old packet format.
+ *
+ * See #pgp_ptag_of_lt_t for the meaning of the values.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_OF_LENGTH_TYPE_MASK 0x03
+
+
+/** Old Packet Format Lengths.
+ * Defines the meanings of the 2 bits for length type in the
+ * old packet format.
+ *
+ * \see RFC4880 4.2.1
+ */
+typedef enum {
+ PGP_PTAG_OLD_LEN_1 = 0x00, /* Packet has a 1 byte length -
+ * header is 2 bytes long. */
+ PGP_PTAG_OLD_LEN_2 = 0x01, /* Packet has a 2 byte length -
+ * header is 3 bytes long. */
+ PGP_PTAG_OLD_LEN_4 = 0x02, /* Packet has a 4 byte
+ * length - header is 5 bytes
+ * long. */
+ PGP_PTAG_OLD_LEN_INDETERMINATE = 0x03 /* Packet has a
+ * indeterminate length. */
+} pgp_ptag_of_lt_t;
+
+
+/** New Packet Format: Mask for content tag.
+ * In the new packet format the 6 rightmost bits
+ * are the content tag. This is the mask to apply
+ * to the packet tag. Note that you need to
+ * shift by #PGP_PTAG_NF_CONTENT_TAG_SHIFT bits.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_NF_CONTENT_TAG_MASK 0x3f
+/** New Packet Format: Offset for the content tag.
+ * As described at #PGP_PTAG_NF_CONTENT_TAG_MASK the
+ * content tag needs to be shifted after being masked
+ * out from the Packet Tag.
+ *
+ * \see RFC4880 4.2
+ */
+#define PGP_PTAG_NF_CONTENT_TAG_SHIFT 0
+
+/* PTag Content Tags */
+/***************************/
+
+/** Package Tags (aka Content Tags) and signature subpacket types.
+ * This enumerates all rfc-defined packet tag values and the
+ * signature subpacket type values that we understand.
+ *
+ * \see RFC4880 4.3
+ * \see RFC4880 5.2.3.1
+ */
+typedef enum {
+ PGP_PTAG_CT_RESERVED = 0, /* Reserved - a packet tag must
+ * not have this value */
+ PGP_PTAG_CT_PK_SESSION_KEY = 1, /* Public-Key Encrypted Session
+ * Key Packet */
+ PGP_PTAG_CT_SIGNATURE = 2, /* Signature Packet */
+ PGP_PTAG_CT_SK_SESSION_KEY = 3, /* Symmetric-Key Encrypted Session
+ * Key Packet */
+ PGP_PTAG_CT_1_PASS_SIG = 4, /* One-Pass Signature
+ * Packet */
+ PGP_PTAG_CT_SECRET_KEY = 5, /* Secret Key Packet */
+ PGP_PTAG_CT_PUBLIC_KEY = 6, /* Public Key Packet */
+ PGP_PTAG_CT_SECRET_SUBKEY = 7, /* Secret Subkey Packet */
+ PGP_PTAG_CT_COMPRESSED = 8, /* Compressed Data Packet */
+ PGP_PTAG_CT_SE_DATA = 9,/* Symmetrically Encrypted Data Packet */
+ PGP_PTAG_CT_MARKER = 10,/* Marker Packet */
+ PGP_PTAG_CT_LITDATA = 11, /* Literal Data Packet */
+ PGP_PTAG_CT_TRUST = 12, /* Trust Packet */
+ PGP_PTAG_CT_USER_ID = 13, /* User ID Packet */
+ PGP_PTAG_CT_PUBLIC_SUBKEY = 14, /* Public Subkey Packet */
+ PGP_PTAG_CT_RESERVED2 = 15, /* reserved */
+ PGP_PTAG_CT_RESERVED3 = 16, /* reserved */
+ PGP_PTAG_CT_USER_ATTR = 17, /* User Attribute Packet */
+ PGP_PTAG_CT_SE_IP_DATA = 18, /* Sym. Encrypted and Integrity
+ * Protected Data Packet */
+ PGP_PTAG_CT_MDC = 19, /* Modification Detection Code Packet */
+
+ PGP_PARSER_PTAG = 0x100,/* Internal Use: The packet is the "Packet
+ * Tag" itself - used when callback sends
+ * back the PTag. */
+ PGP_PTAG_RAW_SS = 0x101,/* Internal Use: content is raw sig subtag */
+ PGP_PTAG_SS_ALL = 0x102,/* Internal Use: select all subtags */
+ PGP_PARSER_PACKET_END = 0x103,
+
+ /* signature subpackets (0x200-2ff) (type+0x200) */
+ /* only those we can parse are listed here */
+ PGP_PTAG_SIG_SUBPKT_BASE = 0x200, /* Base for signature
+ * subpacket types - All
+ * signature type values
+ * are relative to this
+ * value. */
+ PGP_PTAG_SS_CREATION_TIME = 0x200 + 2, /* signature creation time */
+ PGP_PTAG_SS_EXPIRATION_TIME = 0x200 + 3, /* signature
+ * expiration time */
+
+ PGP_PTAG_SS_EXPORT_CERT = 0x200 + 4, /* exportable certification */
+ PGP_PTAG_SS_TRUST = 0x200 + 5, /* trust signature */
+ PGP_PTAG_SS_REGEXP = 0x200 + 6, /* regular expression */
+ PGP_PTAG_SS_REVOCABLE = 0x200 + 7, /* revocable */
+ PGP_PTAG_SS_KEY_EXPIRY = 0x200 + 9, /* key expiration
+ * time */
+ PGP_PTAG_SS_RESERVED = 0x200 + 10, /* reserved */
+ PGP_PTAG_SS_PREFERRED_SKA = 0x200 + 11, /* preferred symmetric
+ * algs */
+ PGP_PTAG_SS_REVOCATION_KEY = 0x200 + 12, /* revocation key */
+ PGP_PTAG_SS_ISSUER_KEY_ID = 0x200 + 16, /* issuer key ID */
+ PGP_PTAG_SS_NOTATION_DATA = 0x200 + 20, /* notation data */
+ PGP_PTAG_SS_PREFERRED_HASH = 0x200 + 21, /* preferred hash
+ * algs */
+ PGP_PTAG_SS_PREF_COMPRESS = 0x200 + 22, /* preferred
+ * compression
+ * algorithms */
+ PGP_PTAG_SS_KEYSERV_PREFS = 0x200 + 23, /* key server
+ * preferences */
+ PGP_PTAG_SS_PREF_KEYSERV = 0x200 + 24, /* Preferred Key
+ * Server */
+ PGP_PTAG_SS_PRIMARY_USER_ID = 0x200 + 25, /* primary User ID */
+ PGP_PTAG_SS_POLICY_URI = 0x200 + 26, /* Policy URI */
+ PGP_PTAG_SS_KEY_FLAGS = 0x200 + 27, /* key flags */
+ PGP_PTAG_SS_SIGNERS_USER_ID = 0x200 + 28, /* Signer's User ID */
+ PGP_PTAG_SS_REVOCATION_REASON = 0x200 + 29, /* reason for
+ * revocation */
+ PGP_PTAG_SS_FEATURES = 0x200 + 30, /* features */
+ PGP_PTAG_SS_SIGNATURE_TARGET = 0x200 + 31, /* signature target */
+ PGP_PTAG_SS_EMBEDDED_SIGNATURE = 0x200 + 32, /* embedded signature */
+
+ PGP_PTAG_SS_USERDEFINED00 = 0x200 + 100, /* internal or
+ * user-defined */
+ PGP_PTAG_SS_USERDEFINED01 = 0x200 + 101,
+ PGP_PTAG_SS_USERDEFINED02 = 0x200 + 102,
+ PGP_PTAG_SS_USERDEFINED03 = 0x200 + 103,
+ PGP_PTAG_SS_USERDEFINED04 = 0x200 + 104,
+ PGP_PTAG_SS_USERDEFINED05 = 0x200 + 105,
+ PGP_PTAG_SS_USERDEFINED06 = 0x200 + 106,
+ PGP_PTAG_SS_USERDEFINED07 = 0x200 + 107,
+ PGP_PTAG_SS_USERDEFINED08 = 0x200 + 108,
+ PGP_PTAG_SS_USERDEFINED09 = 0x200 + 109,
+ PGP_PTAG_SS_USERDEFINED10 = 0x200 + 110,
+
+ /* pseudo content types */
+ PGP_PTAG_CT_LITDATA_HEADER = 0x300,
+ PGP_PTAG_CT_LITDATA_BODY = 0x300 + 1,
+ PGP_PTAG_CT_SIGNATURE_HEADER = 0x300 + 2,
+ PGP_PTAG_CT_SIGNATURE_FOOTER = 0x300 + 3,
+ PGP_PTAG_CT_ARMOUR_HEADER = 0x300 + 4,
+ PGP_PTAG_CT_ARMOUR_TRAILER = 0x300 + 5,
+ PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER = 0x300 + 6,
+ PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY = 0x300 + 7,
+ PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER = 0x300 + 8,
+ PGP_PTAG_CT_UNARMOURED_TEXT = 0x300 + 9,
+ PGP_PTAG_CT_ENCRYPTED_SECRET_KEY = 0x300 + 10, /* In this case the
+ * algorithm specific
+ * fields will not be
+ * initialised */
+ PGP_PTAG_CT_SE_DATA_HEADER = 0x300 + 11,
+ PGP_PTAG_CT_SE_DATA_BODY = 0x300 + 12,
+ PGP_PTAG_CT_SE_IP_DATA_HEADER = 0x300 + 13,
+ PGP_PTAG_CT_SE_IP_DATA_BODY = 0x300 + 14,
+ PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY = 0x300 + 15,
+
+ /* commands to the callback */
+ PGP_GET_PASSPHRASE = 0x400,
+ PGP_GET_SECKEY = 0x400 + 1,
+
+ /* Errors */
+ PGP_PARSER_ERROR = 0x500, /* Internal Use: Parser Error */
+ PGP_PARSER_ERRCODE = 0x500 + 1 /* Internal Use: Parser Error
+ * with errcode returned */
+} pgp_content_enum;
+
+enum {
+ PGP_REVOCATION_NO_REASON = 0,
+ PGP_REVOCATION_SUPERSEDED = 1,
+ PGP_REVOCATION_COMPROMISED = 2,
+ PGP_REVOCATION_RETIRED = 3,
+ PGP_REVOCATION_NO_LONGER_VALID = 0x20
+};
+
+/** Structure to hold one error code */
+typedef struct {
+ pgp_errcode_t errcode;
+} pgp_parser_errcode_t;
+
+/** Structure to hold one packet tag.
+ * \see RFC4880 4.2
+ */
+typedef struct {
+ unsigned new_format; /* Whether this packet tag is new
+ * (1) or old format (0) */
+ unsigned type; /* content_tag value - See
+ * #pgp_content_enum for meanings */
+ pgp_ptag_of_lt_t length_type; /* Length type (#pgp_ptag_of_lt_t)
+ * - only if this packet tag is old
+ * format. Set to 0 if new format. */
+ unsigned length; /* The length of the packet. This value
+ * is set when we read and compute the length
+ * information, not at the same moment we
+ * create the packet tag structure. Only
+ * defined if #readc is set. *//* XXX: Ben, is this correct? */
+ unsigned position; /* The position (within the
+ * current reader) of the packet */
+ unsigned size; /* number of bits */
+} pgp_ptag_t;
+
+/** Public Key Algorithm Numbers.
+ * OpenPGP assigns a unique Algorithm Number to each algorithm that is part of OpenPGP.
+ *
+ * This lists algorithm numbers for public key algorithms.
+ *
+ * \see RFC4880 9.1
+ */
+typedef enum {
+ PGP_PKA_NOTHING = 0, /* No PKA */
+ PGP_PKA_RSA = 1, /* RSA (Encrypt or Sign) */
+ PGP_PKA_RSA_ENCRYPT_ONLY = 2, /* RSA Encrypt-Only (deprecated -
+ * \see RFC4880 13.5) */
+ PGP_PKA_RSA_SIGN_ONLY = 3, /* RSA Sign-Only (deprecated -
+ * \see RFC4880 13.5) */
+ PGP_PKA_ELGAMAL = 16, /* Elgamal (Encrypt-Only) */
+ PGP_PKA_DSA = 17, /* DSA (Digital Signature Algorithm) */
+ PGP_PKA_RESERVED_ELLIPTIC_CURVE = 18, /* Reserved for Elliptic
+ * Curve */
+ PGP_PKA_RESERVED_ECDSA = 19, /* Reserved for ECDSA */
+ PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN = 20, /* Deprecated. */
+ PGP_PKA_RESERVED_DH = 21, /* Reserved for Diffie-Hellman
+ * (X9.42, as defined for
+ * IETF-S/MIME) */
+ PGP_PKA_PRIVATE00 = 100,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE01 = 101,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE02 = 102,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE03 = 103,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE04 = 104,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE05 = 105,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE06 = 106,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE07 = 107,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE08 = 108,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE09 = 109,/* Private/Experimental Algorithm */
+ PGP_PKA_PRIVATE10 = 110 /* Private/Experimental Algorithm */
+} pgp_pubkey_alg_t;
+
+/** Structure to hold one DSA public key params.
+ *
+ * \see RFC4880 5.5.2
+ */
+typedef struct {
+ BIGNUM *p; /* DSA prime p */
+ BIGNUM *q; /* DSA group order q */
+ BIGNUM *g; /* DSA group generator g */
+ BIGNUM *y; /* DSA public key value y (= g^x mod p
+ * with x being the secret) */
+} pgp_dsa_pubkey_t;
+
+/** Structure to hold an RSA public key.
+ *
+ * \see RFC4880 5.5.2
+ */
+typedef struct {
+ BIGNUM *n; /* RSA public modulus n */
+ BIGNUM *e; /* RSA public encryption exponent e */
+} pgp_rsa_pubkey_t;
+
+/** Structure to hold an ElGamal public key params.
+ *
+ * \see RFC4880 5.5.2
+ */
+typedef struct {
+ BIGNUM *p; /* ElGamal prime p */
+ BIGNUM *g; /* ElGamal group generator g */
+ BIGNUM *y; /* ElGamal public key value y (= g^x mod p
+ * with x being the secret) */
+} pgp_elgamal_pubkey_t;
+
+/** Version.
+ * OpenPGP has two different protocol versions: version 3 and version 4.
+ *
+ * \see RFC4880 5.2
+ */
+typedef enum {
+ PGP_V2 = 2, /* Version 2 (essentially the same as v3) */
+ PGP_V3 = 3, /* Version 3 */
+ PGP_V4 = 4 /* Version 4 */
+} pgp_version_t;
+
+/** Structure to hold a pgp public key */
+typedef struct {
+ pgp_version_t version;/* version of the key (v3, v4...) */
+ time_t birthtime;
+ time_t duration;
+ /* validity period of the key in days since
+ * creation. A value of 0 has a special meaning
+ * indicating this key does not expire. Only used with
+ * v3 keys. */
+ unsigned days_valid; /* v4 duration */
+ pgp_pubkey_alg_t alg; /* Public Key Algorithm type */
+ union {
+ pgp_dsa_pubkey_t dsa; /* A DSA public key */
+ pgp_rsa_pubkey_t rsa; /* An RSA public key */
+ pgp_elgamal_pubkey_t elgamal; /* An ElGamal public key */
+ } key; /* Public Key Parameters */
+} pgp_pubkey_t;
+
+/** Structure to hold data for one RSA secret key
+ */
+typedef struct {
+ BIGNUM *d;
+ BIGNUM *p;
+ BIGNUM *q;
+ BIGNUM *u;
+} pgp_rsa_seckey_t;
+
+/** pgp_dsa_seckey_t */
+typedef struct {
+ BIGNUM *x;
+} pgp_dsa_seckey_t;
+
+/** pgp_elgamal_seckey_t */
+typedef struct {
+ BIGNUM *x;
+} pgp_elgamal_seckey_t;
+
+/** s2k_usage_t
+ */
+typedef enum {
+ PGP_S2KU_NONE = 0,
+ PGP_S2KU_ENCRYPTED_AND_HASHED = 254,
+ PGP_S2KU_ENCRYPTED = 255
+} pgp_s2k_usage_t;
+
+/** s2k_specifier_t
+ */
+typedef enum {
+ PGP_S2KS_SIMPLE = 0,
+ PGP_S2KS_SALTED = 1,
+ PGP_S2KS_ITERATED_AND_SALTED = 3
+} pgp_s2k_specifier_t;
+
+/** Symmetric Key Algorithm Numbers.
+ * OpenPGP assigns a unique Algorithm Number to each algorithm that is
+ * part of OpenPGP.
+ *
+ * This lists algorithm numbers for symmetric key algorithms.
+ *
+ * \see RFC4880 9.2
+ */
+typedef enum {
+ PGP_SA_PLAINTEXT = 0, /* Plaintext or unencrypted data */
+ PGP_SA_IDEA = 1, /* IDEA */
+ PGP_SA_TRIPLEDES = 2, /* TripleDES */
+ PGP_SA_CAST5 = 3, /* CAST5 */
+ PGP_SA_BLOWFISH = 4, /* Blowfish */
+ PGP_SA_AES_128 = 7, /* AES with 128-bit key (AES) */
+ PGP_SA_AES_192 = 8, /* AES with 192-bit key */
+ PGP_SA_AES_256 = 9, /* AES with 256-bit key */
+ PGP_SA_TWOFISH = 10, /* Twofish with 256-bit key (TWOFISH) */
+ PGP_SA_CAMELLIA_128 = 100, /* Camellia with 128-bit key (CAMELLIA) */
+ PGP_SA_CAMELLIA_192 = 101, /* Camellia with 192-bit key */
+ PGP_SA_CAMELLIA_256 = 102 /* Camellia with 256-bit key */
+} pgp_symm_alg_t;
+
+#define PGP_SA_DEFAULT_CIPHER PGP_SA_CAST5
+
+/** Hashing Algorithm Numbers.
+ * OpenPGP assigns a unique Algorithm Number to each algorithm that is
+ * part of OpenPGP.
+ *
+ * This lists algorithm numbers for hash algorithms.
+ *
+ * \see RFC4880 9.4
+ */
+typedef enum {
+ PGP_HASH_UNKNOWN = -1, /* used to indicate errors */
+ PGP_HASH_MD5 = 1, /* MD5 */
+ PGP_HASH_SHA1 = 2, /* SHA-1 */
+ PGP_HASH_RIPEMD = 3, /* RIPEMD160 */
+
+ PGP_HASH_SHA256 = 8, /* SHA256 */
+ PGP_HASH_SHA384 = 9, /* SHA384 */
+ PGP_HASH_SHA512 = 10, /* SHA512 */
+ PGP_HASH_SHA224 = 11 /* SHA224 */
+} pgp_hash_alg_t;
+
+#define PGP_DEFAULT_HASH_ALGORITHM PGP_HASH_SHA256
+
+void pgp_calc_mdc_hash(const uint8_t *,
+ const size_t,
+ const uint8_t *,
+ const unsigned,
+ uint8_t *);
+unsigned pgp_is_hash_alg_supported(const pgp_hash_alg_t *);
+
+/* Maximum block size for symmetric crypto */
+#define PGP_MAX_BLOCK_SIZE 16
+
+/* Maximum key size for symmetric crypto */
+#define PGP_MAX_KEY_SIZE 32
+
+/* Salt size for hashing */
+#define PGP_SALT_SIZE 8
+
+/* Max hash size */
+#define PGP_MAX_HASH_SIZE 64
+
+/** pgp_seckey_t
+ */
+typedef struct pgp_seckey_t {
+ pgp_pubkey_t pubkey; /* public key */
+ pgp_s2k_usage_t s2k_usage;
+ pgp_s2k_specifier_t s2k_specifier;
+ pgp_symm_alg_t alg; /* symmetric alg */
+ pgp_hash_alg_t hash_alg; /* hash algorithm */
+ uint8_t salt[PGP_SALT_SIZE];
+ unsigned octetc;
+ uint8_t iv[PGP_MAX_BLOCK_SIZE];
+ union {
+ pgp_rsa_seckey_t rsa;
+ pgp_dsa_seckey_t dsa;
+ pgp_elgamal_seckey_t elgamal;
+ } key;
+ unsigned checksum;
+ uint8_t *checkhash;
+} pgp_seckey_t;
+
+/** Signature Type.
+ * OpenPGP defines different signature types that allow giving
+ * different meanings to signatures. Signature types include 0x10 for
+ * generitc User ID certifications (used when Ben signs Weasel's key),
+ * Subkey binding signatures, document signatures, key revocations,
+ * etc.
+ *
+ * Different types are used in different places, and most make only
+ * sense in their intended location (for instance a subkey binding has
+ * no place on a UserID).
+ *
+ * \see RFC4880 5.2.1
+ */
+typedef enum {
+ PGP_SIG_BINARY = 0x00, /* Signature of a binary document */
+ PGP_SIG_TEXT = 0x01, /* Signature of a canonical text document */
+ PGP_SIG_STANDALONE = 0x02, /* Standalone signature */
+
+ PGP_CERT_GENERIC = 0x10,/* Generic certification of a User ID and
+ * Public Key packet */
+ PGP_CERT_PERSONA = 0x11,/* Persona certification of a User ID and
+ * Public Key packet */
+ PGP_CERT_CASUAL = 0x12, /* Casual certification of a User ID and
+ * Public Key packet */
+ PGP_CERT_POSITIVE = 0x13, /* Positive certification of a
+ * User ID and Public Key packet */
+
+ PGP_SIG_SUBKEY = 0x18, /* Subkey Binding Signature */
+ PGP_SIG_PRIMARY = 0x19, /* Primary Key Binding Signature */
+ PGP_SIG_DIRECT = 0x1f, /* Signature directly on a key */
+
+ PGP_SIG_REV_KEY = 0x20, /* Key revocation signature */
+ PGP_SIG_REV_SUBKEY = 0x28, /* Subkey revocation signature */
+ PGP_SIG_REV_CERT = 0x30,/* Certification revocation signature */
+
+ PGP_SIG_TIMESTAMP = 0x40, /* Timestamp signature */
+
+ PGP_SIG_3RD_PARTY = 0x50/* Third-Party Confirmation signature */
+} pgp_sig_type_t;
+
+/** Struct to hold params of an RSA signature */
+typedef struct pgp_rsa_sig_t {
+ BIGNUM *sig; /* the signature value (m^d % n) */
+} pgp_rsa_sig_t;
+
+/** Struct to hold params of a DSA signature */
+typedef struct pgp_dsa_sig_t {
+ BIGNUM *r; /* DSA value r */
+ BIGNUM *s; /* DSA value s */
+} pgp_dsa_sig_t;
+
+/** pgp_elgamal_signature_t */
+typedef struct pgp_elgamal_sig_t {
+ BIGNUM *r;
+ BIGNUM *s;
+} pgp_elgamal_sig_t;
+
+#define PGP_KEY_ID_SIZE 8
+#define PGP_FINGERPRINT_SIZE 20
+
+/** Struct to hold a signature packet.
+ *
+ * \see RFC4880 5.2.2
+ * \see RFC4880 5.2.3
+ */
+typedef struct pgp_sig_info_t {
+ pgp_version_t version;/* signature version number */
+ pgp_sig_type_t type; /* signature type value */
+ time_t birthtime; /* creation time of the signature */
+ time_t duration; /* number of seconds it's valid for */
+ uint8_t signer_id[PGP_KEY_ID_SIZE]; /* Eight-octet key ID
+ * of signer */
+ pgp_pubkey_alg_t key_alg; /* public key algorithm number */
+ pgp_hash_alg_t hash_alg; /* hashing algorithm number */
+ union {
+ pgp_rsa_sig_t rsa; /* An RSA Signature */
+ pgp_dsa_sig_t dsa; /* A DSA Signature */
+ pgp_elgamal_sig_t elgamal; /* deprecated */
+ pgp_data_t unknown; /* private or experimental */
+ } sig; /* signature params */
+ size_t v4_hashlen;
+ uint8_t *v4_hashed;
+ unsigned birthtime_set:1;
+ unsigned signer_id_set:1;
+ unsigned duration_set:1;
+} pgp_sig_info_t;
+
+/** Struct used when parsing a signature */
+typedef struct pgp_sig_t {
+ pgp_sig_info_t info; /* The signature information */
+ /* The following fields are only used while parsing the signature */
+ uint8_t hash2[2]; /* high 2 bytes of hashed value */
+ size_t v4_hashstart; /* only valid if accumulate is set */
+ pgp_hash_t *hash; /* the hash filled in for the data so far */
+} pgp_sig_t;
+
+/** The raw bytes of a signature subpacket */
+
+typedef struct pgp_ss_raw_t {
+ pgp_content_enum tag;
+ size_t length;
+ uint8_t *raw;
+} pgp_ss_raw_t;
+
+/** Signature Subpacket : Trust Level */
+
+typedef struct pgp_ss_trust_t {
+ uint8_t level; /* Trust Level */
+ uint8_t amount; /* Amount */
+} pgp_ss_trust_t;
+
+/** Signature Subpacket : Notation Data */
+typedef struct pgp_ss_notation_t {
+ pgp_data_t flags;
+ pgp_data_t name;
+ pgp_data_t value;
+} pgp_ss_notation_t;
+
+/** Signature Subpacket : Signature Target */
+typedef struct pgp_ss_sig_target_t {
+ pgp_pubkey_alg_t pka_alg;
+ pgp_hash_alg_t hash_alg;
+ pgp_data_t hash;
+} pgp_ss_sig_target_t;
+
+/** pgp_subpacket_t */
+typedef struct pgp_subpacket_t {
+ size_t length;
+ uint8_t *raw;
+} pgp_subpacket_t;
+
+/** Types of Compression */
+typedef enum {
+ PGP_C_NONE = 0,
+ PGP_C_ZIP = 1,
+ PGP_C_ZLIB = 2,
+ PGP_C_BZIP2 = 3
+} pgp_compression_type_t;
+
+/** pgp_one_pass_sig_t */
+typedef struct {
+ uint8_t version;
+ pgp_sig_type_t sig_type;
+ pgp_hash_alg_t hash_alg;
+ pgp_pubkey_alg_t key_alg;
+ uint8_t keyid[PGP_KEY_ID_SIZE];
+ unsigned nested;
+} pgp_one_pass_sig_t;
+
+/** Signature Subpacket : Revocation Key */
+typedef struct {
+ uint8_t class;
+ uint8_t algid;
+ uint8_t fingerprint[PGP_FINGERPRINT_SIZE];
+} pgp_ss_revocation_key_t;
+
+/** Signature Subpacket : Revocation Reason */
+typedef struct {
+ uint8_t code;
+ char *reason;
+} pgp_ss_revocation_t;
+
+/** litdata_type_t */
+typedef enum {
+ PGP_LDT_BINARY = 'b',
+ PGP_LDT_TEXT = 't',
+ PGP_LDT_UTF8 = 'u',
+ PGP_LDT_LOCAL = 'l',
+ PGP_LDT_LOCAL2 = '1'
+} pgp_litdata_enum;
+
+/** pgp_litdata_header_t */
+typedef struct {
+ pgp_litdata_enum format;
+ char filename[256];
+ time_t mtime;
+} pgp_litdata_header_t;
+
+/** pgp_litdata_body_t */
+typedef struct {
+ unsigned length;
+ uint8_t *data;
+ void *mem; /* pgp_memory_t pointer */
+} pgp_litdata_body_t;
+
+/** pgp_header_var_t */
+typedef struct {
+ char *key;
+ char *value;
+} pgp_header_var_t;
+
+/** pgp_headers_t */
+typedef struct {
+ pgp_header_var_t *headers;
+ unsigned headerc;
+} pgp_headers_t;
+
+/** pgp_armour_header_t */
+typedef struct {
+ const char *type;
+ pgp_headers_t headers;
+} pgp_armour_header_t;
+
+/** pgp_fixed_body_t */
+typedef struct pgp_fixed_body_t {
+ unsigned length;
+ uint8_t data[8192]; /* \todo fix hard-coded value? */
+} pgp_fixed_body_t;
+
+/** pgp_dyn_body_t */
+typedef struct pgp_dyn_body_t {
+ unsigned length;
+ uint8_t *data;
+} pgp_dyn_body_t;
+
+enum {
+ PGP_SE_IP_DATA_VERSION = 1,
+ PGP_PKSK_V3 = 3
+};
+
+/** pgp_pk_sesskey_params_rsa_t */
+typedef struct {
+ BIGNUM *encrypted_m;
+ BIGNUM *m;
+} pgp_pk_sesskey_params_rsa_t;
+
+/** pgp_pk_sesskey_params_elgamal_t */
+typedef struct {
+ BIGNUM *g_to_k;
+ BIGNUM *encrypted_m;
+} pgp_pk_sesskey_params_elgamal_t;
+
+/** pgp_pk_sesskey_params_t */
+typedef union {
+ pgp_pk_sesskey_params_rsa_t rsa;
+ pgp_pk_sesskey_params_elgamal_t elgamal;
+} pgp_pk_sesskey_params_t;
+
+/** pgp_pk_sesskey_t */
+typedef struct {
+ unsigned version;
+ uint8_t key_id[PGP_KEY_ID_SIZE];
+ pgp_pubkey_alg_t alg;
+ pgp_pk_sesskey_params_t params;
+ pgp_symm_alg_t symm_alg;
+ uint8_t key[PGP_MAX_KEY_SIZE];
+ uint16_t checksum;
+} pgp_pk_sesskey_t;
+
+/** pgp_seckey_passphrase_t */
+typedef struct {
+ const pgp_seckey_t *seckey;
+ char **passphrase; /* point somewhere that gets filled
+ * in to work around constness of
+ * content */
+} pgp_seckey_passphrase_t;
+
+/** pgp_get_seckey_t */
+typedef struct {
+ const pgp_seckey_t **seckey;
+ const pgp_pk_sesskey_t *pk_sesskey;
+} pgp_get_seckey_t;
+
+/** pgp_parser_union_content_t */
+typedef union {
+ const char *error;
+ pgp_parser_errcode_t errcode;
+ pgp_ptag_t ptag;
+ pgp_pubkey_t pubkey;
+ pgp_data_t trust;
+ uint8_t *userid;
+ pgp_data_t userattr;
+ pgp_sig_t sig;
+ pgp_ss_raw_t ss_raw;
+ pgp_ss_trust_t ss_trust;
+ unsigned ss_revocable;
+ time_t ss_time;
+ uint8_t ss_issuer[PGP_KEY_ID_SIZE];
+ pgp_ss_notation_t ss_notation;
+ pgp_subpacket_t packet;
+ pgp_compression_type_t compressed;
+ pgp_one_pass_sig_t one_pass_sig;
+ pgp_data_t ss_skapref;
+ pgp_data_t ss_hashpref;
+ pgp_data_t ss_zpref;
+ pgp_data_t ss_key_flags;
+ pgp_data_t ss_key_server_prefs;
+ unsigned ss_primary_userid;
+ char *ss_regexp;
+ char *ss_policy;
+ char *ss_keyserv;
+ pgp_ss_revocation_key_t ss_revocation_key;
+ pgp_data_t ss_userdef;
+ pgp_data_t ss_unknown;
+ pgp_litdata_header_t litdata_header;
+ pgp_litdata_body_t litdata_body;
+ pgp_dyn_body_t mdc;
+ pgp_data_t ss_features;
+ pgp_ss_sig_target_t ss_sig_target;
+ pgp_data_t ss_embedded_sig;
+ pgp_ss_revocation_t ss_revocation;
+ pgp_seckey_t seckey;
+ uint8_t *ss_signer;
+ pgp_armour_header_t armour_header;
+ const char *armour_trailer;
+ pgp_headers_t cleartext_head;
+ pgp_fixed_body_t cleartext_body;
+ struct pgp_hash_t *cleartext_trailer;
+ pgp_dyn_body_t unarmoured_text;
+ pgp_pk_sesskey_t pk_sesskey;
+ pgp_seckey_passphrase_t skey_passphrase;
+ unsigned se_ip_data_header;
+ pgp_dyn_body_t se_ip_data_body;
+ pgp_fixed_body_t se_data_body;
+ pgp_get_seckey_t get_seckey;
+} pgp_contents_t;
+
+/** pgp_packet_t */
+struct pgp_packet_t {
+ pgp_content_enum tag; /* type of contents */
+ uint8_t critical; /* for sig subpackets */
+ pgp_contents_t u; /* union for contents */
+};
+
+/** pgp_fingerprint_t */
+typedef struct {
+ uint8_t fingerprint[PGP_FINGERPRINT_SIZE];
+ unsigned length;
+ pgp_hash_alg_t hashtype;
+} pgp_fingerprint_t;
+
+int pgp_keyid(uint8_t *, const size_t, const pgp_pubkey_t *, pgp_hash_alg_t);
+int pgp_fingerprint(pgp_fingerprint_t *, const pgp_pubkey_t *, pgp_hash_alg_t);
+
+void pgp_finish(void);
+void pgp_pubkey_free(pgp_pubkey_t *);
+void pgp_userid_free(uint8_t **);
+void pgp_data_free(pgp_data_t *);
+void pgp_sig_free(pgp_sig_t *);
+void pgp_ss_notation_free(pgp_ss_notation_t *);
+void pgp_ss_revocation_free(pgp_ss_revocation_t *);
+void pgp_ss_sig_target_free(pgp_ss_sig_target_t *);
+
+void pgp_subpacket_free(pgp_subpacket_t *);
+void pgp_parser_content_free(pgp_packet_t *);
+void pgp_seckey_free(pgp_seckey_t *);
+void pgp_pk_sesskey_free(pgp_pk_sesskey_t *);
+
+int pgp_print_packet(pgp_printstate_t *, const pgp_packet_t *);
+
+#define DYNARRAY(type, arr) \
+ unsigned arr##c; unsigned arr##vsize; type *arr##s
+
+#define EXPAND_ARRAY(str, arr) do { \
+ if (str->arr##c == str->arr##vsize) { \
+ void *__newarr; \
+ char *__newarrc; \
+ unsigned __newsize; \
+ __newsize = (str->arr##vsize * 2) + 10; \
+ if ((__newarrc = __newarr = realloc(str->arr##s, \
+ __newsize * sizeof(*str->arr##s))) == NULL) { \
+ (void) fprintf(stderr, "EXPAND_ARRAY - bad realloc\n"); \
+ } else { \
+ (void) memset(&__newarrc[str->arr##vsize * sizeof(*str->arr##s)], \
+ 0x0, (__newsize - str->arr##vsize) * sizeof(*str->arr##s)); \
+ str->arr##s = __newarr; \
+ str->arr##vsize = __newsize; \
+ } \
+ } \
+} while(/*CONSTCOND*/0)
+
+/** pgp_keydata_key_t
+ */
+typedef union {
+ pgp_pubkey_t pubkey;
+ pgp_seckey_t seckey;
+} pgp_keydata_key_t;
+
+
+/* sigpacket_t */
+typedef struct {
+ uint8_t **userid;
+ pgp_subpacket_t *packet;
+} sigpacket_t;
+
+/* user revocation info */
+typedef struct pgp_revoke_t {
+ uint32_t uid; /* index in uid array */
+ uint8_t code; /* revocation code */
+ char *reason; /* c'mon, spill the beans */
+} pgp_revoke_t;
+
+/** signature subpackets */
+typedef struct pgp_subsig_t {
+ uint32_t uid; /* index in userid array in key */
+ pgp_sig_t sig; /* trust signature */
+ uint8_t trustlevel; /* level of trust */
+ uint8_t trustamount; /* amount of trust */
+} pgp_subsig_t;
+
+/* describes a user's key */
+struct pgp_key_t {
+ DYNARRAY(uint8_t *, uid); /* array of user ids */
+ DYNARRAY(pgp_subpacket_t, packet); /* array of raw subpackets */
+ DYNARRAY(pgp_subsig_t, subsig); /* array of signature subkeys */
+ DYNARRAY(pgp_revoke_t, revoke); /* array of signature revocations */
+ pgp_content_enum type; /* type of key */
+ pgp_keydata_key_t key; /* pubkey/seckey data */
+ pgp_pubkey_t sigkey; /* signature key */
+ uint8_t sigid[PGP_KEY_ID_SIZE];
+ pgp_fingerprint_t sigfingerprint; /* pgp signature fingerprint */
+ pgp_pubkey_t enckey; /* encryption key */
+ uint8_t encid[PGP_KEY_ID_SIZE];
+ pgp_fingerprint_t encfingerprint; /* pgp encryption id fingerprint */
+ uint32_t uid0; /* primary uid index in uids array */
+ uint8_t revoked; /* key has been revoked */
+ pgp_revoke_t revocation; /* revocation reason */
+};
+
+#define MDC_PKT_TAG 0xd3
+
+#endif /* PACKET_H_ */
diff --git a/libs/netpgp/src/lib/reader.c b/libs/netpgp/src/lib/reader.c
new file mode 100644
index 00000000..be00b094
--- /dev/null
+++ b/libs/netpgp/src/lib/reader.c
@@ -0,0 +1,2415 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: reader.c,v 1.49 2012/03/05 02:20:18 christos Exp $");
+#endif
+
+#include
+#include
+
+#ifdef HAVE_SYS_MMAN_H
+#include
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_DIRECT_H
+#include
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_IDEA_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_IDEA_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_AES_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_DES_H
+#include
+#endif
+
+#include
+#include
+#include
+
+#ifdef HAVE_TERMIOS_H
+#include
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include
+#endif
+
+#include "errors.h"
+#include "crypto.h"
+#include "create.h"
+#include "signature.h"
+#include "packet.h"
+#include "packet-parse.h"
+#include "packet-show.h"
+#include "packet.h"
+#include "keyring.h"
+#include "readerwriter.h"
+#include "netpgpsdk.h"
+#include "netpgpdefs.h"
+#include "netpgpdigest.h"
+
+/* data from partial blocks is queued up in virtual block in stream */
+static int
+read_partial_data(pgp_stream_t *stream, void *dest, size_t length)
+{
+ unsigned n;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "fd_reader: coalesced data, off %d\n",
+ stream->virtualoff);
+ }
+ n = MIN(stream->virtualc - stream->virtualoff, (unsigned)length);
+ (void) memcpy(dest, &stream->virtualpkt[stream->virtualoff], n);
+ stream->virtualoff += n;
+ if (stream->virtualoff == stream->virtualc) {
+ free(stream->virtualpkt);
+ stream->virtualpkt = NULL;
+ stream->virtualc = stream->virtualoff = 0;
+ }
+ return (int)n;
+}
+
+/* get a pass phrase from the user */
+int
+pgp_getpassphrase(void *in, char *phrase, size_t size)
+{
+ char *p;
+
+ if (in == NULL) {
+ while ((p = getpass("netpgp passphrase: ")) == NULL) {
+ }
+ (void) snprintf(phrase, size, "%s", p);
+ } else {
+ if (fgets(phrase, (int)size, in) == NULL) {
+ return 0;
+ }
+ phrase[strlen(phrase) - 1] = 0x0;
+ }
+ return 1;
+}
+
+/**
+ * \ingroup Internal_Readers_Generic
+ * \brief Starts reader stack
+ * \param stream Parse settings
+ * \param reader Reader to use
+ * \param destroyer Destroyer to use
+ * \param vp Reader-specific arg
+ */
+void
+pgp_reader_set(pgp_stream_t *stream,
+ pgp_reader_func_t *reader,
+ pgp_reader_destroyer_t *destroyer,
+ void *vp)
+{
+ stream->readinfo.reader = reader;
+ stream->readinfo.destroyer = destroyer;
+ stream->readinfo.arg = vp;
+}
+
+/**
+ * \ingroup Internal_Readers_Generic
+ * \brief Adds to reader stack
+ * \param stream Parse settings
+ * \param reader Reader to use
+ * \param destroyer Reader's destroyer
+ * \param vp Reader-specific arg
+ */
+void
+pgp_reader_push(pgp_stream_t *stream,
+ pgp_reader_func_t *reader,
+ pgp_reader_destroyer_t *destroyer,
+ void *vp)
+{
+ pgp_reader_t *readinfo;
+
+ if ((readinfo = calloc(1, sizeof(*readinfo))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_push: bad alloc\n");
+ } else {
+ *readinfo = stream->readinfo;
+ (void) memset(&stream->readinfo, 0x0, sizeof(stream->readinfo));
+ stream->readinfo.next = readinfo;
+ stream->readinfo.parent = stream;
+
+ /* should copy accumulate flags from other reader? RW */
+ stream->readinfo.accumulate = readinfo->accumulate;
+
+ pgp_reader_set(stream, reader, destroyer, vp);
+ }
+}
+
+/**
+ * \ingroup Internal_Readers_Generic
+ * \brief Removes from reader stack
+ * \param stream Parse settings
+ */
+void
+pgp_reader_pop(pgp_stream_t *stream)
+{
+ pgp_reader_t *next = stream->readinfo.next;
+
+ stream->readinfo = *next;
+ free(next);
+}
+
+/**
+ * \ingroup Internal_Readers_Generic
+ * \brief Gets arg from reader
+ * \param readinfo Reader info
+ * \return Pointer to reader info's arg
+ */
+void *
+pgp_reader_get_arg(pgp_reader_t *readinfo)
+{
+ return readinfo->arg;
+}
+
+/**************************************************************************/
+
+#define CRC24_POLY 0x1864cfbL
+
+enum {
+ NONE = 0,
+ BEGIN_PGP_MESSAGE,
+ BEGIN_PGP_PUBLIC_KEY_BLOCK,
+ BEGIN_PGP_PRIVATE_KEY_BLOCK,
+ BEGIN_PGP_MULTI,
+ BEGIN_PGP_SIGNATURE,
+
+ END_PGP_MESSAGE,
+ END_PGP_PUBLIC_KEY_BLOCK,
+ END_PGP_PRIVATE_KEY_BLOCK,
+ END_PGP_MULTI,
+ END_PGP_SIGNATURE,
+
+ BEGIN_PGP_SIGNED_MESSAGE
+};
+
+/**
+ * \struct dearmour_t
+ */
+typedef struct {
+ enum {
+ OUTSIDE_BLOCK = 0,
+ BASE64,
+ AT_TRAILER_NAME
+ } state;
+ int lastseen;
+ pgp_stream_t *parse_info;
+ unsigned seen_nl:1;
+ unsigned prev_nl:1;
+ unsigned allow_headers_without_gap:1;
+ /* !< allow headers in armoured data that are
+ * not separated from the data by a blank line
+ * */
+ unsigned allow_no_gap:1;
+ /* !< allow no blank line at the start of
+ * armoured data */
+ unsigned allow_trailing_whitespace:1;
+ /* !< allow armoured stuff to have trailing
+ * whitespace where we wouldn't strictly expect
+ * it */
+ /* it is an error to get a cleartext message without a sig */
+ unsigned expect_sig:1;
+ unsigned got_sig:1;
+ /* base64 stuff */
+ unsigned buffered;
+ uint8_t buffer[3];
+ unsigned eof64;
+ uint32_t checksum;
+ uint32_t read_checksum;
+ /* unarmoured text blocks */
+ uint8_t unarmoured[NETPGP_BUFSIZ];
+ size_t unarmoredc;
+ /* pushed back data (stored backwards) */
+ uint8_t *pushback;
+ unsigned pushbackc;
+ /* armoured block headers */
+ pgp_headers_t headers;
+} dearmour_t;
+
+static void
+push_back(dearmour_t *dearmour, const uint8_t *buf,
+ unsigned length)
+{
+ unsigned n;
+
+ if (dearmour->pushback) {
+ (void) fprintf(stderr, "push_back: already pushed back\n");
+ } else if ((dearmour->pushback = calloc(1, length)) == NULL) {
+ (void) fprintf(stderr, "push_back: bad alloc\n");
+ } else {
+ for (n = 0; n < length; ++n) {
+ dearmour->pushback[n] = buf[(length - n) - 1];
+ }
+ dearmour->pushbackc = length;
+ }
+}
+
+/* this struct holds a textual header line */
+typedef struct headerline_t {
+ const char *s; /* the header line */
+ size_t len; /* its length */
+ int type; /* the defined type */
+} headerline_t;
+
+static headerline_t headerlines[] = {
+ { "BEGIN PGP MESSAGE", 17, BEGIN_PGP_MESSAGE },
+ { "BEGIN PGP PUBLIC KEY BLOCK", 26, BEGIN_PGP_PUBLIC_KEY_BLOCK },
+ { "BEGIN PGP PRIVATE KEY BLOCK",27, BEGIN_PGP_PRIVATE_KEY_BLOCK },
+ { "BEGIN PGP MESSAGE, PART ", 25, BEGIN_PGP_MULTI },
+ { "BEGIN PGP SIGNATURE", 19, BEGIN_PGP_SIGNATURE },
+
+ { "END PGP MESSAGE", 15, END_PGP_MESSAGE },
+ { "END PGP PUBLIC KEY BLOCK", 24, END_PGP_PUBLIC_KEY_BLOCK },
+ { "END PGP PRIVATE KEY BLOCK", 25, END_PGP_PRIVATE_KEY_BLOCK },
+ { "END PGP MESSAGE, PART ", 22, END_PGP_MULTI },
+ { "END PGP SIGNATURE", 17, END_PGP_SIGNATURE },
+
+ { "BEGIN PGP SIGNED MESSAGE", 24, BEGIN_PGP_SIGNED_MESSAGE },
+
+ { NULL, 0, -1 }
+};
+
+/* search through the table of header lines */
+static int
+findheaderline(char *headerline)
+{
+ headerline_t *hp;
+
+ for (hp = headerlines ; hp->s ; hp++) {
+ if (strncmp(headerline, hp->s, hp->len) == 0) {
+ break;
+ }
+ }
+ return hp->type;
+}
+
+static int
+set_lastseen_headerline(dearmour_t *dearmour, char *hdr, pgp_error_t **errors)
+{
+ int lastseen;
+ int prev;
+
+ prev = dearmour->lastseen;
+ if ((lastseen = findheaderline(hdr)) == -1) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "Unrecognised Header Line %s", hdr);
+ return 0;
+ }
+ dearmour->lastseen = lastseen;
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("set header: hdr=%s, dearmour->lastseen=%d, prev=%d\n",
+ hdr, dearmour->lastseen, prev);
+ }
+ switch (dearmour->lastseen) {
+ case NONE:
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "Unrecognised last seen Header Line %s", hdr);
+ break;
+
+ case END_PGP_MESSAGE:
+ if (prev != BEGIN_PGP_MESSAGE) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Got END PGP MESSAGE, but not after BEGIN");
+ }
+ break;
+
+ case END_PGP_PUBLIC_KEY_BLOCK:
+ if (prev != BEGIN_PGP_PUBLIC_KEY_BLOCK) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Got END PGP PUBLIC KEY BLOCK, but not after BEGIN");
+ }
+ break;
+
+ case END_PGP_PRIVATE_KEY_BLOCK:
+ if (prev != BEGIN_PGP_PRIVATE_KEY_BLOCK) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Got END PGP PRIVATE KEY BLOCK, but not after BEGIN");
+ }
+ break;
+
+ case BEGIN_PGP_MULTI:
+ case END_PGP_MULTI:
+ PGP_ERROR_1(errors, PGP_E_R_UNSUPPORTED, "%s",
+ "Multi-part messages are not yet supported");
+ break;
+
+ case END_PGP_SIGNATURE:
+ if (prev != BEGIN_PGP_SIGNATURE) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Got END PGP SIGNATURE, but not after BEGIN");
+ }
+ break;
+
+ case BEGIN_PGP_MESSAGE:
+ case BEGIN_PGP_PUBLIC_KEY_BLOCK:
+ case BEGIN_PGP_PRIVATE_KEY_BLOCK:
+ case BEGIN_PGP_SIGNATURE:
+ case BEGIN_PGP_SIGNED_MESSAGE:
+ break;
+ }
+ return 1;
+}
+
+static int
+read_char(pgp_stream_t *stream, dearmour_t *dearmour,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo,
+ unsigned skip)
+{
+ uint8_t c;
+
+ do {
+ if (dearmour->pushbackc) {
+ c = dearmour->pushback[--dearmour->pushbackc];
+ if (dearmour->pushbackc == 0) {
+ free(dearmour->pushback);
+ dearmour->pushback = NULL;
+ }
+ } else if (pgp_stacked_read(stream, &c, 1, errors, readinfo,
+ cbinfo) != 1) {
+ return -1;
+ }
+ } while (skip && c == '\r');
+ dearmour->prev_nl = dearmour->seen_nl;
+ dearmour->seen_nl = c == '\n';
+ return c;
+}
+
+static int
+eat_whitespace(pgp_stream_t *stream, int first,
+ dearmour_t *dearmour,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo,
+ unsigned skip)
+{
+ int c = first;
+
+ while (c == ' ' || c == '\t') {
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, skip);
+ }
+ return c;
+}
+
+static int
+read_and_eat_whitespace(pgp_stream_t *stream, dearmour_t *dearmour,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo,
+ unsigned skip)
+{
+ int c;
+
+ do {
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, skip);
+ } while (c == ' ' || c == '\t');
+ return c;
+}
+
+static void
+flush(dearmour_t *dearmour, pgp_cbdata_t *cbinfo)
+{
+ pgp_packet_t content;
+
+ if (dearmour->unarmoredc > 0) {
+ content.u.unarmoured_text.data = dearmour->unarmoured;
+ content.u.unarmoured_text.length = (unsigned)dearmour->unarmoredc;
+ CALLBACK(PGP_PTAG_CT_UNARMOURED_TEXT, cbinfo, &content);
+ dearmour->unarmoredc = 0;
+ }
+}
+
+static int
+unarmoured_read_char(pgp_stream_t *stream, dearmour_t *dearmour,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo,
+ unsigned skip)
+{
+ int c;
+
+ do {
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 0);
+ if (c < 0) {
+ return c;
+ }
+ dearmour->unarmoured[dearmour->unarmoredc++] = c;
+ if (dearmour->unarmoredc == sizeof(dearmour->unarmoured)) {
+ flush(dearmour, cbinfo);
+ }
+ } while (skip && c == '\r');
+ return c;
+}
+
+/**
+ * \param headers
+ * \param key
+ *
+ * \return header value if found, otherwise NULL
+ */
+static const char *
+find_header(pgp_headers_t *headers, const char *key)
+{
+ unsigned n;
+
+ for (n = 0; n < headers->headerc; ++n) {
+ if (strcmp(headers->headers[n].key, key) == 0) {
+ return headers->headers[n].value;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * \param dest
+ * \param src
+ */
+static void
+dup_headers(pgp_headers_t *dest, const pgp_headers_t *src)
+{
+ unsigned n;
+
+ if ((dest->headers = calloc(src->headerc, sizeof(*dest->headers))) == NULL) {
+ (void) fprintf(stderr, "dup_headers: bad alloc\n");
+ } else {
+ dest->headerc = src->headerc;
+ for (n = 0; n < src->headerc; ++n) {
+ dest->headers[n].key = netpgp_strdup(src->headers[n].key);
+ dest->headers[n].value = netpgp_strdup(src->headers[n].value);
+ }
+ }
+}
+
+/*
+ * Note that this skips CRs so implementations always see just straight LFs
+ * as line terminators
+ */
+static int
+process_dash_escaped(pgp_stream_t *stream, dearmour_t *dearmour,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ pgp_fixed_body_t *body;
+ pgp_packet_t content2;
+ pgp_packet_t content;
+ const char *hashstr;
+ pgp_hash_t *hash;
+ int total;
+
+ body = &content.u.cleartext_body;
+ if ((hash = calloc(1, sizeof(*hash))) == NULL) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "process_dash_escaped: bad alloc");
+ return -1;
+ }
+ hashstr = find_header(&dearmour->headers, "Hash");
+ if (hashstr) {
+ pgp_hash_alg_t alg;
+
+ alg = pgp_str_to_hash_alg(hashstr);
+ if (!pgp_is_hash_alg_supported(&alg)) {
+ free(hash);
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "Unsupported hash algorithm '%s'", hashstr);
+ return -1;
+ }
+ if (alg == PGP_HASH_UNKNOWN) {
+ free(hash);
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "Unknown hash algorithm '%s'", hashstr);
+ return -1;
+ }
+ pgp_hash_any(hash, alg);
+ } else {
+ pgp_hash_md5(hash);
+ }
+
+ if (!hash->init(hash)) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "can't initialise hash");
+ return -1;
+ }
+
+ body->length = 0;
+ total = 0;
+ for (;;) {
+ int c;
+ unsigned count;
+
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 1);
+ if (c < 0) {
+ return -1;
+ }
+ if (dearmour->prev_nl && c == '-') {
+ if ((c = read_char(stream, dearmour, errors, readinfo, cbinfo,
+ 0)) < 0) {
+ return -1;
+ }
+ if (c != ' ') {
+ /* then this had better be a trailer! */
+ if (c != '-') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Bad dash-escaping");
+ }
+ for (count = 2; count < 5; ++count) {
+ if ((c = read_char(stream, dearmour, errors,
+ readinfo, cbinfo, 0)) < 0) {
+ return -1;
+ }
+ if (c != '-') {
+ PGP_ERROR_1(errors,
+ PGP_E_R_BAD_FORMAT, "%s",
+ "Bad dash-escaping (2)");
+ }
+ }
+ dearmour->state = AT_TRAILER_NAME;
+ break;
+ }
+ /* otherwise we read the next character */
+ if ((c = read_char(stream, dearmour, errors, readinfo, cbinfo,
+ 0)) < 0) {
+ return -1;
+ }
+ }
+ if (c == '\n' && body->length) {
+ if (memchr(body->data + 1, '\n', body->length - 1)
+ != NULL) {
+ (void) fprintf(stderr,
+ "process_dash_escaped: newline found\n");
+ return -1;
+ }
+ if (body->data[0] == '\n') {
+ hash->add(hash, (const uint8_t *)"\r", 1);
+ }
+ hash->add(hash, body->data, body->length);
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "Got body:\n%s\n", body->data);
+ }
+ CALLBACK(PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
+ &content);
+ body->length = 0;
+ }
+ body->data[body->length++] = c;
+ total += 1;
+ if (body->length == sizeof(body->data)) {
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "Got body (2):\n%s\n",
+ body->data);
+ }
+ CALLBACK(PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
+ &content);
+ body->length = 0;
+ }
+ }
+ if (body->data[0] != '\n') {
+ (void) fprintf(stderr,
+ "process_dash_escaped: no newline in body data\n");
+ return -1;
+ }
+ if (body->length != 1) {
+ (void) fprintf(stderr,
+ "process_dash_escaped: bad body length\n");
+ return -1;
+ }
+ /* don't send that one character, because it's part of the trailer */
+ (void) memset(&content2, 0x0, sizeof(content2));
+ CALLBACK(PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER, cbinfo, &content2);
+ return total;
+}
+
+static int
+add_header(dearmour_t *dearmour, const char *key, const char *value)
+{
+ int n;
+
+ /*
+ * Check that the header is valid
+ */
+ if (strcmp(key, "Version") == 0 ||
+ strcmp(key, "Comment") == 0 ||
+ strcmp(key, "MessageID") == 0 ||
+ strcmp(key, "Hash") == 0 ||
+ strcmp(key, "Charset") == 0) {
+ n = dearmour->headers.headerc;
+ dearmour->headers.headers = realloc(dearmour->headers.headers,
+ (n + 1) * sizeof(*dearmour->headers.headers));
+ if (dearmour->headers.headers == NULL) {
+ (void) fprintf(stderr, "add_header: bad alloc\n");
+ return 0;
+ }
+ dearmour->headers.headers[n].key = netpgp_strdup(key);
+ dearmour->headers.headers[n].value = netpgp_strdup(value);
+ dearmour->headers.headerc = n + 1;
+ return 1;
+ }
+ return 0;
+}
+
+/* \todo what does a return value of 0 indicate? 1 is good, -1 is bad */
+static int
+parse_headers(pgp_stream_t *stream, dearmour_t *dearmour, pgp_error_t **errors,
+ pgp_reader_t * readinfo, pgp_cbdata_t * cbinfo)
+{
+ unsigned nbuf;
+ unsigned size;
+ unsigned first = 1;
+ char *buf;
+ int ret = 1;
+
+ nbuf = 0;
+ size = 80;
+ if ((buf = calloc(1, size)) == NULL) {
+ (void) fprintf(stderr, "parse_headers: bad calloc\n");
+ return -1;
+ }
+ for (;;) {
+ int c;
+
+ if ((c = read_char(stream, dearmour, errors, readinfo, cbinfo, 1)) < 0) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Unexpected EOF");
+ ret = -1;
+ break;
+ }
+ if (c == '\n') {
+ char *s;
+
+ if (nbuf == 0) {
+ break;
+ }
+
+ if (nbuf >= size) {
+ (void) fprintf(stderr,
+ "parse_headers: bad size\n");
+ return -1;
+ }
+ buf[nbuf] = '\0';
+
+ if ((s = strchr(buf, ':')) == NULL) {
+ if (!first && !dearmour->allow_headers_without_gap) {
+ /*
+ * then we have seriously malformed
+ * armour
+ */
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "No colon in armour header");
+ ret = -1;
+ break;
+ } else {
+ if (first &&
+ !(dearmour->allow_headers_without_gap || dearmour->allow_no_gap)) {
+ PGP_ERROR_1(errors,
+ PGP_E_R_BAD_FORMAT,
+ "%s", "No colon in"
+ " armour header (2)");
+ /*
+ * then we have a nasty
+ * armoured block with no
+ * headers, not even a blank
+ * line.
+ */
+ buf[nbuf] = '\n';
+ push_back(dearmour, (uint8_t *) buf, nbuf + 1);
+ ret = -1;
+ break;
+ }
+ }
+ } else {
+ *s = '\0';
+ if (s[1] != ' ') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "No space in armour header");
+ ret = -1;
+ goto end;
+ }
+ if (!add_header(dearmour, buf, s + 2)) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "Invalid header %s", buf);
+ ret = -1;
+ goto end;
+ }
+ nbuf = 0;
+ }
+ first = 0;
+ } else {
+ if (size <= nbuf + 1) {
+ size += size + 80;
+ buf = realloc(buf, size);
+ if (buf == NULL) {
+ (void) fprintf(stderr, "bad alloc\n");
+ ret = -1;
+ goto end;
+ }
+ }
+ buf[nbuf++] = c;
+ }
+ }
+
+end:
+ free(buf);
+
+ return ret;
+}
+
+static int
+read4(pgp_stream_t *stream, dearmour_t *dearmour, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo,
+ int *pc, unsigned *pn, uint32_t *pl)
+{
+ int n, c;
+ uint32_t l = 0;
+
+ for (n = 0; n < 4; ++n) {
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 1);
+ if (c < 0) {
+ dearmour->eof64 = 1;
+ return -1;
+ }
+ if (c == '-' || c == '=') {
+ break;
+ }
+ l <<= 6;
+ if (c >= 'A' && c <= 'Z') {
+ l += (uint32_t)(c - 'A');
+ } else if (c >= 'a' && c <= 'z') {
+ l += (uint32_t)(c - 'a') + 26;
+ } else if (c >= '0' && c <= '9') {
+ l += (uint32_t)(c - '0') + 52;
+ } else if (c == '+') {
+ l += 62;
+ } else if (c == '/') {
+ l += 63;
+ } else {
+ --n;
+ l >>= 6;
+ }
+ }
+
+ *pc = c;
+ *pn = n;
+ *pl = l;
+
+ return 4;
+}
+
+unsigned
+pgp_crc24(unsigned checksum, uint8_t c)
+{
+ unsigned i;
+
+ checksum ^= c << 16;
+ for (i = 0; i < 8; i++) {
+ checksum <<= 1;
+ if (checksum & 0x1000000)
+ checksum ^= CRC24_POLY;
+ }
+ return (unsigned)(checksum & 0xffffffL);
+}
+
+static int
+decode64(pgp_stream_t *stream, dearmour_t *dearmour, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ unsigned n;
+ int n2;
+ uint32_t l;
+ int c;
+ int ret;
+
+ if (dearmour->buffered) {
+ (void) fprintf(stderr, "decode64: bad dearmour->buffered\n");
+ return 0;
+ }
+
+ ret = read4(stream, dearmour, errors, readinfo, cbinfo, &c, &n, &l);
+ if (ret < 0) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Badly formed base64");
+ return 0;
+ }
+ if (n == 3) {
+ if (c != '=') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Badly terminated base64 (2)");
+ return 0;
+ }
+ dearmour->buffered = 2;
+ dearmour->eof64 = 1;
+ l >>= 2;
+ } else if (n == 2) {
+ if (c != '=') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Badly terminated base64 (3)");
+ return 0;
+ }
+ dearmour->buffered = 1;
+ dearmour->eof64 = 1;
+ l >>= 4;
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 0);
+ if (c != '=') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Badly terminated base64");
+ return 0;
+ }
+ } else if (n == 0) {
+ if (!dearmour->prev_nl || c != '=') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Badly terminated base64 (4)");
+ return 0;
+ }
+ dearmour->buffered = 0;
+ } else {
+ if (n != 4) {
+ (void) fprintf(stderr,
+ "decode64: bad n (!= 4)\n");
+ return 0;
+ }
+ dearmour->buffered = 3;
+ if (c == '-' || c == '=') {
+ (void) fprintf(stderr, "decode64: bad c\n");
+ return 0;
+ }
+ }
+
+ if (dearmour->buffered < 3 && dearmour->buffered > 0) {
+ /* then we saw padding */
+ if (c != '=') {
+ (void) fprintf(stderr, "decode64: bad c (=)\n");
+ return 0;
+ }
+ c = read_and_eat_whitespace(stream, dearmour, errors, readinfo, cbinfo,
+ 1);
+ if (c != '\n') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "No newline at base64 end");
+ return 0;
+ }
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 0);
+ if (c != '=') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "No checksum at base64 end");
+ return 0;
+ }
+ }
+ if (c == '=') {
+ /* now we are at the checksum */
+ ret = read4(stream, dearmour, errors, readinfo, cbinfo, &c, &n,
+ &dearmour->read_checksum);
+ if (ret < 0 || n != 4) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Error in checksum");
+ return 0;
+ }
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 1);
+ if (dearmour->allow_trailing_whitespace)
+ c = eat_whitespace(stream, c, dearmour, errors, readinfo, cbinfo,
+ 1);
+ if (c != '\n') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Badly terminated checksum");
+ return 0;
+ }
+ c = read_char(stream, dearmour, errors, readinfo, cbinfo, 0);
+ if (c != '-') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Bad base64 trailer (2)");
+ return 0;
+ }
+ }
+ if (c == '-') {
+ for (n = 0; n < 4; ++n)
+ if (read_char(stream, dearmour, errors, readinfo, cbinfo,
+ 0) != '-') {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Bad base64 trailer");
+ return 0;
+ }
+ dearmour->eof64 = 1;
+ } else {
+ if (!dearmour->buffered) {
+ (void) fprintf(stderr, "decode64: not buffered\n");
+ return 0;
+ }
+ }
+
+ for (n = 0; n < dearmour->buffered; ++n) {
+ dearmour->buffer[n] = (uint8_t)l;
+ l >>= 8;
+ }
+
+ for (n2 = dearmour->buffered - 1; n2 >= 0; --n2)
+ dearmour->checksum = pgp_crc24((unsigned)dearmour->checksum,
+ dearmour->buffer[n2]);
+
+ if (dearmour->eof64 && dearmour->read_checksum != dearmour->checksum) {
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Checksum mismatch");
+ return 0;
+ }
+ return 1;
+}
+
+static void
+base64(dearmour_t *dearmour)
+{
+ dearmour->state = BASE64;
+ dearmour->checksum = CRC24_INIT;
+ dearmour->eof64 = 0;
+ dearmour->buffered = 0;
+}
+
+/* This reader is rather strange in that it can generate callbacks for */
+/* content - this is because plaintext is not encapsulated in PGP */
+/* packets... it also calls back for the text between the blocks. */
+
+static int
+armoured_data_reader(pgp_stream_t *stream, void *dest_, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ pgp_packet_t content;
+ dearmour_t *dearmour;
+ unsigned first;
+ uint8_t *dest = dest_;
+ char buf[1024];
+ int saved;
+ int ret;
+
+ dearmour = pgp_reader_get_arg(readinfo);
+ saved = (int)length;
+ if (dearmour->eof64 && !dearmour->buffered) {
+ if (dearmour->state != OUTSIDE_BLOCK &&
+ dearmour->state != AT_TRAILER_NAME) {
+ (void) fprintf(stderr,
+ "armoured_data_reader: bad dearmour state\n");
+ return 0;
+ }
+ }
+
+ while (length > 0) {
+ unsigned count;
+ unsigned n;
+ int c;
+
+ flush(dearmour, cbinfo);
+ switch (dearmour->state) {
+ case OUTSIDE_BLOCK:
+ /*
+ * This code returns EOF rather than EARLY_EOF
+ * because if we don't see a header line at all, then
+ * it is just an EOF (and not a BLOCK_END)
+ */
+ while (!dearmour->seen_nl) {
+ if ((c = unarmoured_read_char(stream, dearmour, errors,
+ readinfo, cbinfo, 1)) < 0) {
+ return 0;
+ }
+ }
+
+ /*
+ * flush at this point so we definitely have room for
+ * the header, and so we can easily erase it from the
+ * buffer
+ */
+ flush(dearmour, cbinfo);
+ /* Find and consume the 5 leading '-' */
+ for (count = 0; count < 5; ++count) {
+ if ((c = unarmoured_read_char(stream, dearmour, errors,
+ readinfo, cbinfo, 0)) < 0) {
+ return 0;
+ }
+ if (c != '-') {
+ goto reloop;
+ }
+ }
+
+ /* Now find the block type */
+ for (n = 0; n < sizeof(buf) - 1;) {
+ if ((c = unarmoured_read_char(stream, dearmour, errors,
+ readinfo, cbinfo, 0)) < 0) {
+ return 0;
+ }
+ if (c == '-') {
+ goto got_minus;
+ }
+ buf[n++] = c;
+ }
+ /* then I guess this wasn't a proper header */
+ break;
+
+got_minus:
+ buf[n] = '\0';
+
+ /* Consume trailing '-' */
+ for (count = 1; count < 5; ++count) {
+ if ((c = unarmoured_read_char(stream, dearmour, errors,
+ readinfo, cbinfo, 0)) < 0) {
+ return 0;
+ }
+ if (c != '-') {
+ /* wasn't a header after all */
+ goto reloop;
+ }
+ }
+
+ /* Consume final NL */
+ if ((c = unarmoured_read_char(stream, dearmour, errors, readinfo,
+ cbinfo, 1)) < 0) {
+ return 0;
+ }
+ if (dearmour->allow_trailing_whitespace) {
+ if ((c = eat_whitespace(stream, c, dearmour, errors,
+ readinfo, cbinfo, 1)) < 0) {
+ return 0;
+ }
+ }
+ if (c != '\n') {
+ /* wasn't a header line after all */
+ break;
+ }
+
+ /*
+ * Now we've seen the header, scrub it from the
+ * buffer
+ */
+ dearmour->unarmoredc = 0;
+
+ /*
+ * But now we've seen a header line, then errors are
+ * EARLY_EOF
+ */
+ if ((ret = parse_headers(stream, dearmour, errors, readinfo,
+ cbinfo)) <= 0) {
+ return -1;
+ }
+
+ if (!set_lastseen_headerline(dearmour, buf, errors)) {
+ return -1;
+ }
+
+ if (strcmp(buf, "BEGIN PGP SIGNED MESSAGE") == 0) {
+ dup_headers(&content.u.cleartext_head,
+ &dearmour->headers);
+ CALLBACK(PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER,
+ cbinfo,
+ &content);
+ ret = process_dash_escaped(stream, dearmour, errors,
+ readinfo, cbinfo);
+ if (ret <= 0) {
+ return ret;
+ }
+ } else {
+ content.u.armour_header.type = buf;
+ content.u.armour_header.headers =
+ dearmour->headers;
+ (void) memset(&dearmour->headers, 0x0,
+ sizeof(dearmour->headers));
+ CALLBACK(PGP_PTAG_CT_ARMOUR_HEADER, cbinfo,
+ &content);
+ base64(dearmour);
+ }
+ break;
+
+ case BASE64:
+ first = 1;
+ while (length > 0) {
+ if (!dearmour->buffered) {
+ if (!dearmour->eof64) {
+ ret = decode64(stream, dearmour,
+ errors, readinfo, cbinfo);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+ if (!dearmour->buffered) {
+ if (!dearmour->eof64) {
+ (void) fprintf(stderr,
+"armoured_data_reader: bad dearmour eof64\n");
+ return 0;
+ }
+ if (first) {
+ dearmour->state =
+ AT_TRAILER_NAME;
+ goto reloop;
+ }
+ return -1;
+ }
+ }
+ if (!dearmour->buffered) {
+ (void) fprintf(stderr,
+ "armoured_data_reader: bad dearmour buffered\n");
+ return 0;
+ }
+ *dest = dearmour->buffer[--dearmour->buffered];
+ ++dest;
+ --length;
+ first = 0;
+ }
+ if (dearmour->eof64 && !dearmour->buffered) {
+ dearmour->state = AT_TRAILER_NAME;
+ }
+ break;
+
+ case AT_TRAILER_NAME:
+ for (n = 0; n < sizeof(buf) - 1;) {
+ if ((c = read_char(stream, dearmour, errors, readinfo,
+ cbinfo, 0)) < 0) {
+ return -1;
+ }
+ if (c == '-') {
+ goto got_minus2;
+ }
+ buf[n++] = c;
+ }
+ /* then I guess this wasn't a proper trailer */
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT, "%s",
+ "Bad ASCII armour trailer");
+ break;
+
+got_minus2:
+ buf[n] = '\0';
+
+ if (!set_lastseen_headerline(dearmour, buf, errors)) {
+ return -1;
+ }
+
+ /* Consume trailing '-' */
+ for (count = 1; count < 5; ++count) {
+ if ((c = read_char(stream, dearmour, errors, readinfo,
+ cbinfo, 0)) < 0) {
+ return -1;
+ }
+ if (c != '-') {
+ /* wasn't a trailer after all */
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s",
+ "Bad ASCII armour trailer (2)");
+ }
+ }
+
+ /* Consume final NL */
+ if ((c = read_char(stream, dearmour, errors, readinfo, cbinfo,
+ 1)) < 0) {
+ return -1;
+ }
+ if (dearmour->allow_trailing_whitespace) {
+ if ((c = eat_whitespace(stream, c, dearmour, errors,
+ readinfo, cbinfo, 1)) < 0) {
+ return 0;
+ }
+ }
+ if (c != '\n') {
+ /* wasn't a trailer line after all */
+ PGP_ERROR_1(errors, PGP_E_R_BAD_FORMAT,
+ "%s", "Bad ASCII armour trailer (3)");
+ }
+
+ if (strncmp(buf, "BEGIN ", 6) == 0) {
+ if (!set_lastseen_headerline(dearmour, buf,
+ errors)) {
+ return -1;
+ }
+ if ((ret = parse_headers(stream, dearmour, errors,
+ readinfo, cbinfo)) <= 0) {
+ return ret;
+ }
+ content.u.armour_header.type = buf;
+ content.u.armour_header.headers =
+ dearmour->headers;
+ (void) memset(&dearmour->headers, 0x0,
+ sizeof(dearmour->headers));
+ CALLBACK(PGP_PTAG_CT_ARMOUR_HEADER, cbinfo,
+ &content);
+ base64(dearmour);
+ } else {
+ content.u.armour_trailer = buf;
+ CALLBACK(PGP_PTAG_CT_ARMOUR_TRAILER, cbinfo,
+ &content);
+ dearmour->state = OUTSIDE_BLOCK;
+ }
+ break;
+ }
+reloop:
+ continue;
+ }
+
+ return saved;
+}
+
+static void
+armoured_data_destroyer(pgp_reader_t *readinfo)
+{
+ free(pgp_reader_get_arg(readinfo));
+}
+
+/**
+ * \ingroup Core_Readers_Armour
+ * \brief Pushes dearmouring reader onto stack
+ * \param parse_info Usual structure containing information about to how to do the parse
+ * \sa pgp_reader_pop_dearmour()
+ */
+void
+pgp_reader_push_dearmour(pgp_stream_t *parse_info)
+/*
+ * This function originally had these params to cater for packets which
+ * didn't strictly match the RFC. The initial 0.5 release is only going to
+ * support strict checking. If it becomes desirable to support loose checking
+ * of armoured packets and these params are reinstated, parse_headers() must
+ * be fixed so that these flags work correctly.
+ *
+ * // Allow headers in armoured data that are not separated from the data by a
+ * blank line unsigned without_gap,
+ *
+ * // Allow no blank line at the start of armoured data unsigned no_gap,
+ *
+ * //Allow armoured data to have trailing whitespace where we strictly would not
+ * expect it unsigned trailing_whitespace
+ */
+{
+ dearmour_t *dearmour;
+
+ if ((dearmour = calloc(1, sizeof(*dearmour))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_push_dearmour: bad alloc\n");
+ } else {
+ dearmour->seen_nl = 1;
+ /*
+ dearmour->allow_headers_without_gap=without_gap;
+ dearmour->allow_no_gap=no_gap;
+ dearmour->allow_trailing_whitespace=trailing_whitespace;
+ */
+ dearmour->expect_sig = 0;
+ dearmour->got_sig = 0;
+
+ pgp_reader_push(parse_info, armoured_data_reader,
+ armoured_data_destroyer, dearmour);
+ }
+}
+
+/**
+ * \ingroup Core_Readers_Armour
+ * \brief Pops dearmour reader from stock
+ * \param stream
+ * \sa pgp_reader_push_dearmour()
+ */
+void
+pgp_reader_pop_dearmour(pgp_stream_t *stream)
+{
+ dearmour_t *dearmour;
+
+ dearmour = pgp_reader_get_arg(pgp_readinfo(stream));
+ free(dearmour);
+ pgp_reader_pop(stream);
+}
+
+/**************************************************************************/
+
+/* this is actually used for *decrypting* */
+typedef struct {
+ uint8_t decrypted[1024 * 15];
+ size_t c;
+ size_t off;
+ pgp_crypt_t *decrypt;
+ pgp_region_t *region;
+ unsigned prevplain:1;
+} encrypted_t;
+
+static int
+encrypted_data_reader(pgp_stream_t *stream, void *dest,
+ size_t length,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ encrypted_t *encrypted;
+ char *cdest;
+ int saved;
+
+ encrypted = pgp_reader_get_arg(readinfo);
+ saved = (int)length;
+ /*
+ * V3 MPIs have the count plain and the cipher is reset after each
+ * count
+ */
+ if (encrypted->prevplain && !readinfo->parent->reading_mpi_len) {
+ if (!readinfo->parent->reading_v3_secret) {
+ (void) fprintf(stderr,
+ "encrypted_data_reader: bad v3 secret\n");
+ return -1;
+ }
+ encrypted->decrypt->decrypt_resync(encrypted->decrypt);
+ encrypted->prevplain = 0;
+ } else if (readinfo->parent->reading_v3_secret &&
+ readinfo->parent->reading_mpi_len) {
+ encrypted->prevplain = 1;
+ }
+ while (length > 0) {
+ if (encrypted->c) {
+ unsigned n;
+
+ /*
+ * if we are reading v3 we should never read
+ * more than we're asked for */
+ if (length < encrypted->c &&
+ (readinfo->parent->reading_v3_secret ||
+ readinfo->parent->exact_read)) {
+ (void) fprintf(stderr,
+ "encrypted_data_reader: bad v3 read\n");
+ return 0;
+ }
+ n = (int)MIN(length, encrypted->c);
+ (void) memcpy(dest,
+ encrypted->decrypted + encrypted->off, n);
+ encrypted->c -= n;
+ encrypted->off += n;
+ length -= n;
+ cdest = dest;
+ cdest += n;
+ dest = cdest;
+ } else {
+ unsigned n = encrypted->region->length;
+ uint8_t buffer[1024];
+
+ if (!n) {
+ return -1;
+ }
+ if (!encrypted->region->indeterminate) {
+ n -= encrypted->region->readc;
+ if (n == 0) {
+ return (int)(saved - length);
+ }
+ if (n > sizeof(buffer)) {
+ n = sizeof(buffer);
+ }
+ } else {
+ n = sizeof(buffer);
+ }
+
+ /*
+ * we can only read as much as we're asked for
+ * in v3 keys because they're partially
+ * unencrypted! */
+ if ((readinfo->parent->reading_v3_secret ||
+ readinfo->parent->exact_read) && n > length) {
+ n = (unsigned)length;
+ }
+
+ if (!pgp_stacked_limited_read(stream, buffer, n,
+ encrypted->region, errors, readinfo, cbinfo)) {
+ return -1;
+ }
+ if (!readinfo->parent->reading_v3_secret ||
+ !readinfo->parent->reading_mpi_len) {
+ encrypted->c =
+ pgp_decrypt_se_ip(encrypted->decrypt,
+ encrypted->decrypted, buffer, n);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "encrypted", buffer, 16);
+ hexdump(stderr, "decrypted", encrypted->decrypted, 16);
+ }
+ } else {
+ (void) memcpy(
+ &encrypted->decrypted[encrypted->off], buffer, n);
+ encrypted->c = n;
+ }
+
+ if (encrypted->c == 0) {
+ (void) fprintf(stderr,
+ "encrypted_data_reader: 0 decrypted count\n");
+ return 0;
+ }
+
+ encrypted->off = 0;
+ }
+ }
+
+ return saved;
+}
+
+static void
+encrypted_data_destroyer(pgp_reader_t *readinfo)
+{
+ free(pgp_reader_get_arg(readinfo));
+}
+
+/**
+ * \ingroup Core_Readers_SE
+ * \brief Pushes decryption reader onto stack
+ * \sa pgp_reader_pop_decrypt()
+ */
+void
+pgp_reader_push_decrypt(pgp_stream_t *stream, pgp_crypt_t *decrypt,
+ pgp_region_t *region)
+{
+ encrypted_t *encrypted;
+
+ if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_push_decrypted: bad alloc\n");
+ } else {
+ encrypted->decrypt = decrypt;
+ encrypted->region = region;
+ pgp_decrypt_init(encrypted->decrypt);
+ pgp_reader_push(stream, encrypted_data_reader,
+ encrypted_data_destroyer, encrypted);
+ }
+}
+
+/**
+ * \ingroup Core_Readers_Encrypted
+ * \brief Pops decryption reader from stack
+ * \sa pgp_reader_push_decrypt()
+ */
+void
+pgp_reader_pop_decrypt(pgp_stream_t *stream)
+{
+ encrypted_t *encrypted;
+
+ encrypted = pgp_reader_get_arg(pgp_readinfo(stream));
+ encrypted->decrypt->decrypt_finish(encrypted->decrypt);
+ free(encrypted);
+ pgp_reader_pop(stream);
+}
+
+/**************************************************************************/
+
+typedef struct {
+ /* boolean: 0 once we've done the preamble/MDC checks */
+ /* and are reading from the plaintext */
+ int passed_checks;
+ uint8_t *plaintext;
+ size_t plaintext_available;
+ size_t plaintext_offset;
+ pgp_region_t *region;
+ pgp_crypt_t *decrypt;
+} decrypt_se_ip_t;
+
+/*
+ Gets entire SE_IP data packet.
+ Verifies leading preamble
+ Verifies trailing MDC packet
+ Then passes up plaintext as requested
+*/
+static int
+se_ip_data_reader(pgp_stream_t *stream, void *dest_,
+ size_t len,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ decrypt_se_ip_t *se_ip;
+ pgp_region_t decrypted_region;
+ unsigned n = 0;
+
+ se_ip = pgp_reader_get_arg(readinfo);
+ if (!se_ip->passed_checks) {
+ uint8_t *buf = NULL;
+ uint8_t hashed[PGP_SHA1_HASH_SIZE];
+ uint8_t *preamble;
+ uint8_t *plaintext;
+ uint8_t *mdc;
+ uint8_t *mdc_hash;
+ pgp_hash_t hash;
+ size_t b;
+ size_t sz_preamble;
+ size_t sz_mdc_hash;
+ size_t sz_mdc;
+ size_t sz_plaintext;
+
+ pgp_hash_any(&hash, PGP_HASH_SHA1);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr,
+ "se_ip_data_reader: can't init hash\n");
+ return -1;
+ }
+
+ pgp_init_subregion(&decrypted_region, NULL);
+ decrypted_region.length =
+ se_ip->region->length - se_ip->region->readc;
+ if ((buf = calloc(1, decrypted_region.length)) == NULL) {
+ (void) fprintf(stderr, "se_ip_data_reader: bad alloc\n");
+ return -1;
+ }
+
+ /* read entire SE IP packet */
+ if (!pgp_stacked_limited_read(stream, buf, decrypted_region.length,
+ &decrypted_region, errors, readinfo, cbinfo)) {
+ free(buf);
+ return -1;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "SE IP packet", buf, decrypted_region.length);
+ }
+ /* verify leading preamble */
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "preamble", buf, se_ip->decrypt->blocksize);
+ }
+ b = se_ip->decrypt->blocksize;
+ if (buf[b - 2] != buf[b] || buf[b - 1] != buf[b + 1]) {
+ fprintf(stderr,
+ "Bad symmetric decrypt (%02x%02x vs %02x%02x)\n",
+ buf[b - 2], buf[b - 1], buf[b], buf[b + 1]);
+ PGP_ERROR_1(errors, PGP_E_PROTO_BAD_SYMMETRIC_DECRYPT,
+ "%s", "Bad symmetric decrypt when parsing SE IP"
+ " packet");
+ free(buf);
+ return -1;
+ }
+ /* Verify trailing MDC hash */
+
+ sz_preamble = se_ip->decrypt->blocksize + 2;
+ sz_mdc_hash = PGP_SHA1_HASH_SIZE;
+ sz_mdc = 1 + 1 + sz_mdc_hash;
+ sz_plaintext = (decrypted_region.length - sz_preamble) - sz_mdc;
+
+ preamble = buf;
+ plaintext = buf + sz_preamble;
+ mdc = plaintext + sz_plaintext;
+ mdc_hash = mdc + 2;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "plaintext", plaintext, sz_plaintext);
+ hexdump(stderr, "mdc", mdc, sz_mdc);
+ }
+ pgp_calc_mdc_hash(preamble, sz_preamble, plaintext,
+ (unsigned)sz_plaintext, hashed);
+
+ if (memcmp(mdc_hash, hashed, PGP_SHA1_HASH_SIZE) != 0) {
+ PGP_ERROR_1(errors, PGP_E_V_BAD_HASH, "%s",
+ "Bad hash in MDC packet");
+ free(buf);
+ return 0;
+ }
+ /* all done with the checks */
+ /* now can start reading from the plaintext */
+ if (se_ip->plaintext) {
+ (void) fprintf(stderr,
+ "se_ip_data_reader: bad plaintext\n");
+ return 0;
+ }
+ if ((se_ip->plaintext = calloc(1, sz_plaintext)) == NULL) {
+ (void) fprintf(stderr,
+ "se_ip_data_reader: bad alloc\n");
+ return 0;
+ }
+ memcpy(se_ip->plaintext, plaintext, sz_plaintext);
+ se_ip->plaintext_available = sz_plaintext;
+
+ se_ip->passed_checks = 1;
+
+ free(buf);
+ }
+ n = (unsigned)len;
+ if (n > se_ip->plaintext_available) {
+ n = (unsigned)se_ip->plaintext_available;
+ }
+
+ memcpy(dest_, se_ip->plaintext + se_ip->plaintext_offset, n);
+ se_ip->plaintext_available -= n;
+ se_ip->plaintext_offset += n;
+ /* len -= n; - not used at all, for info only */
+
+ return n;
+}
+
+static void
+se_ip_data_destroyer(pgp_reader_t *readinfo)
+{
+ decrypt_se_ip_t *se_ip;
+
+ se_ip = pgp_reader_get_arg(readinfo);
+ free(se_ip->plaintext);
+ free(se_ip);
+}
+
+/**
+ \ingroup Internal_Readers_SEIP
+*/
+void
+pgp_reader_push_se_ip_data(pgp_stream_t *stream, pgp_crypt_t *decrypt,
+ pgp_region_t * region)
+{
+ decrypt_se_ip_t *se_ip;
+
+ if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_push_se_ip_data: bad alloc\n");
+ } else {
+ se_ip->region = region;
+ se_ip->decrypt = decrypt;
+ pgp_reader_push(stream, se_ip_data_reader, se_ip_data_destroyer,
+ se_ip);
+ }
+}
+
+/**
+ \ingroup Internal_Readers_SEIP
+ */
+void
+pgp_reader_pop_se_ip_data(pgp_stream_t *stream)
+{
+ /*
+ * decrypt_se_ip_t
+ * *se_ip=pgp_reader_get_arg(pgp_readinfo(stream));
+ */
+ /* free(se_ip); */
+ pgp_reader_pop(stream);
+}
+
+/**************************************************************************/
+
+/** Arguments for reader_fd
+ */
+typedef struct mmap_reader_t {
+ void *mem; /* memory mapped file */
+ uint64_t size; /* size of file */
+ uint64_t offset; /* current offset in file */
+ int fd; /* file descriptor */
+} mmap_reader_t;
+
+
+/**
+ * \ingroup Core_Readers
+ *
+ * pgp_reader_fd() attempts to read up to "plength" bytes from the file
+ * descriptor in "parse_info" into the buffer starting at "dest" using the
+ * rules contained in "flags"
+ *
+ * \param dest Pointer to previously allocated buffer
+ * \param plength Number of bytes to try to read
+ * \param flags Rules about reading to use
+ * \param readinfo Reader info
+ * \param cbinfo Callback info
+ *
+ * \return n Number of bytes read
+ *
+ * PGP_R_EARLY_EOF and PGP_R_ERROR push errors on the stack
+ */
+static int
+fd_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ mmap_reader_t *reader;
+ int n;
+
+ __PGP_USED(cbinfo);
+ reader = pgp_reader_get_arg(readinfo);
+ if (!stream->coalescing && stream->virtualc && stream->virtualoff < stream->virtualc) {
+ n = read_partial_data(stream, dest, length);
+ } else {
+ n = (int)read(reader->fd, dest, length);
+ }
+ if (n == 0) {
+ return 0;
+ }
+ if (n < 0) {
+ PGP_SYSTEM_ERROR_1(errors, PGP_E_R_READ_FAILED, "read",
+ "file descriptor %d", reader->fd);
+ return -1;
+ }
+ return n;
+}
+
+static void
+reader_fd_destroyer(pgp_reader_t *readinfo)
+{
+ free(pgp_reader_get_arg(readinfo));
+}
+
+/**
+ \ingroup Core_Readers_First
+ \brief Starts stack with file reader
+*/
+
+void
+pgp_reader_set_fd(pgp_stream_t *stream, int fd)
+{
+ mmap_reader_t *reader;
+
+ if ((reader = calloc(1, sizeof(*reader))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_set_fd: bad alloc\n");
+ } else {
+ reader->fd = fd;
+ pgp_reader_set(stream, fd_reader, reader_fd_destroyer, reader);
+ }
+}
+
+/**************************************************************************/
+
+typedef struct {
+ const uint8_t *buffer;
+ size_t length;
+ size_t offset;
+} reader_mem_t;
+
+static int
+mem_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ reader_mem_t *reader = pgp_reader_get_arg(readinfo);
+ unsigned n;
+
+ __PGP_USED(cbinfo);
+ __PGP_USED(errors);
+ if (!stream->coalescing && stream->virtualc && stream->virtualoff < stream->virtualc) {
+ n = read_partial_data(stream, dest, length);
+ } else {
+ if (reader->offset + length > reader->length) {
+ n = (unsigned)(reader->length - reader->offset);
+ } else {
+ n = (unsigned)length;
+ }
+ if (n == (unsigned)0) {
+ return 0;
+ }
+ memcpy(dest, reader->buffer + reader->offset, n);
+ reader->offset += n;
+ }
+ return n;
+}
+
+static void
+mem_destroyer(pgp_reader_t *readinfo)
+{
+ free(pgp_reader_get_arg(readinfo));
+}
+
+/**
+ \ingroup Core_Readers_First
+ \brief Starts stack with memory reader
+*/
+
+void
+pgp_reader_set_memory(pgp_stream_t *stream, const void *buffer,
+ size_t length)
+{
+ reader_mem_t *mem;
+
+ if ((mem = calloc(1, sizeof(*mem))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_set_memory: bad alloc\n");
+ } else {
+ mem->buffer = buffer;
+ mem->length = length;
+ mem->offset = 0;
+ pgp_reader_set(stream, mem_reader, mem_destroyer, mem);
+ }
+}
+
+/**************************************************************************/
+
+/**
+ \ingroup Core_Writers
+ \brief Create and initialise output and mem; Set for writing to mem
+ \param output Address where new output pointer will be set
+ \param mem Address when new mem pointer will be set
+ \param bufsz Initial buffer size (will automatically be increased when necessary)
+ \note It is the caller's responsiblity to free output and mem.
+ \sa pgp_teardown_memory_write()
+*/
+void
+pgp_setup_memory_write(pgp_output_t **output, pgp_memory_t **mem, size_t bufsz)
+{
+ /*
+ * initialise needed structures for writing to memory
+ */
+
+ *output = pgp_output_new();
+ *mem = pgp_memory_new();
+
+ pgp_memory_init(*mem, bufsz);
+
+ pgp_writer_set_memory(*output, *mem);
+}
+
+/**
+ \ingroup Core_Writers
+ \brief Closes writer and frees output and mem
+ \param output
+ \param mem
+ \sa pgp_setup_memory_write()
+*/
+void
+pgp_teardown_memory_write(pgp_output_t *output, pgp_memory_t *mem)
+{
+ pgp_writer_close(output);/* new */
+ pgp_output_delete(output);
+ pgp_memory_free(mem);
+}
+
+/**
+ \ingroup Core_Readers
+ \brief Create parse_info and sets to read from memory
+ \param stream Address where new parse_info will be set
+ \param mem Memory to read from
+ \param arg Reader-specific arg
+ \param callback Callback to use with reader
+ \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
+ \note It is the caller's responsiblity to free parse_info
+ \sa pgp_teardown_memory_read()
+*/
+void
+pgp_setup_memory_read(pgp_io_t *io,
+ pgp_stream_t **stream,
+ pgp_memory_t *mem,
+ void *vp,
+ pgp_cb_ret_t callback(const pgp_packet_t *,
+ pgp_cbdata_t *),
+ unsigned accumulate)
+{
+ *stream = pgp_new(sizeof(**stream));
+ (*stream)->io = (*stream)->cbinfo.io = io;
+ pgp_set_callback(*stream, callback, vp);
+ pgp_reader_set_memory(*stream,
+ pgp_mem_data(mem),
+ pgp_mem_len(mem));
+ if (accumulate) {
+ (*stream)->readinfo.accumulate = 1;
+ }
+}
+
+/**
+ \ingroup Core_Readers
+ \brief Frees stream and mem
+ \param stream
+ \param mem
+ \sa pgp_setup_memory_read()
+*/
+void
+pgp_teardown_memory_read(pgp_stream_t *stream, pgp_memory_t *mem)
+{
+ pgp_stream_delete(stream);
+ pgp_memory_free(mem);
+}
+
+/**
+ \ingroup Core_Writers
+ \brief Create and initialise output and mem; Set for writing to file
+ \param output Address where new output pointer will be set
+ \param filename File to write to
+ \param allow_overwrite Allows file to be overwritten, if set.
+ \return Newly-opened file descriptor
+ \note It is the caller's responsiblity to free output and to close fd.
+ \sa pgp_teardown_file_write()
+*/
+int
+pgp_setup_file_write(pgp_output_t **output, const char *filename,
+ unsigned allow_overwrite)
+{
+ int fd = 0;
+ int flags = 0;
+
+ /*
+ * initialise needed structures for writing to file
+ */
+ if (filename == NULL) {
+ /* write to stdout */
+ fd = STDOUT_FILENO;
+ } else {
+ flags = O_WRONLY | O_CREAT;
+ if (allow_overwrite)
+ flags |= O_TRUNC;
+ else
+ flags |= O_EXCL;
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+ fd = open(filename, flags, 0600);
+ if (fd < 0) {
+ perror(filename);
+ return fd;
+ }
+ }
+ *output = pgp_output_new();
+ pgp_writer_set_fd(*output, fd);
+ return fd;
+}
+
+/**
+ \ingroup Core_Writers
+ \brief Closes writer, frees info, closes fd
+ \param output
+ \param fd
+*/
+void
+pgp_teardown_file_write(pgp_output_t *output, int fd)
+{
+ pgp_writer_close(output);
+ close(fd);
+ pgp_output_delete(output);
+}
+
+/**
+ \ingroup Core_Writers
+ \brief As pgp_setup_file_write, but appends to file
+*/
+int
+pgp_setup_file_append(pgp_output_t **output, const char *filename)
+{
+ int fd;
+
+ /*
+ * initialise needed structures for writing to file
+ */
+#ifdef O_BINARY
+ fd = open(filename, O_WRONLY | O_APPEND | O_BINARY, 0600);
+#else
+ fd = open(filename, O_WRONLY | O_APPEND, 0600);
+#endif
+ if (fd >= 0) {
+ *output = pgp_output_new();
+ pgp_writer_set_fd(*output, fd);
+ }
+ return fd;
+}
+
+/**
+ \ingroup Core_Writers
+ \brief As pgp_teardown_file_write()
+*/
+void
+pgp_teardown_file_append(pgp_output_t *output, int fd)
+{
+ pgp_teardown_file_write(output, fd);
+}
+
+/**
+ \ingroup Core_Readers
+ \brief Creates parse_info, opens file, and sets to read from file
+ \param stream Address where new parse_info will be set
+ \param filename Name of file to read
+ \param vp Reader-specific arg
+ \param callback Callback to use when reading
+ \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
+ \note It is the caller's responsiblity to free parse_info and to close fd
+ \sa pgp_teardown_file_read()
+*/
+int
+pgp_setup_file_read(pgp_io_t *io,
+ pgp_stream_t **stream,
+ const char *filename,
+ void *vp,
+ pgp_cb_ret_t callback(const pgp_packet_t *,
+ pgp_cbdata_t *),
+ unsigned accumulate)
+{
+ int fd;
+
+#ifdef O_BINARY
+ fd = open(filename, O_RDONLY | O_BINARY);
+#else
+ fd = open(filename, O_RDONLY);
+#endif
+ if (fd < 0) {
+ (void) fprintf(io->errs, "can't open \"%s\"\n", filename);
+ return fd;
+ }
+ *stream = pgp_new(sizeof(**stream));
+ (*stream)->io = (*stream)->cbinfo.io = io;
+ pgp_set_callback(*stream, callback, vp);
+#ifdef USE_MMAP_FOR_FILES
+ pgp_reader_set_mmap(*stream, fd);
+#else
+ pgp_reader_set_fd(*stream, fd);
+#endif
+ if (accumulate) {
+ (*stream)->readinfo.accumulate = 1;
+ }
+ return fd;
+}
+
+/**
+ \ingroup Core_Readers
+ \brief Frees stream and closes fd
+ \param stream
+ \param fd
+ \sa pgp_setup_file_read()
+*/
+void
+pgp_teardown_file_read(pgp_stream_t *stream, int fd)
+{
+ close(fd);
+ pgp_stream_delete(stream);
+}
+
+pgp_cb_ret_t
+pgp_litdata_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("pgp_litdata_cb: ");
+ pgp_print_packet(&cbinfo->printstate, pkt);
+ }
+ /* Read data from packet into static buffer */
+ switch (pkt->tag) {
+ case PGP_PTAG_CT_LITDATA_BODY:
+ /* if writer enabled, use it */
+ if (cbinfo->output) {
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("pgp_litdata_cb: length is %u\n",
+ content->litdata_body.length);
+ }
+ pgp_write(cbinfo->output,
+ content->litdata_body.data,
+ content->litdata_body.length);
+ }
+ break;
+
+ case PGP_PTAG_CT_LITDATA_HEADER:
+ /* ignore */
+ break;
+
+ default:
+ break;
+ }
+
+ return PGP_RELEASE_MEMORY;
+}
+
+pgp_cb_ret_t
+pgp_pk_sesskey_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+ unsigned from;
+ pgp_io_t *io;
+
+ io = cbinfo->io;
+ if (pgp_get_debug_level(__FILE__)) {
+ pgp_print_packet(&cbinfo->printstate, pkt);
+ }
+ /* Read data from packet into static buffer */
+ switch (pkt->tag) {
+ case PGP_PTAG_CT_PK_SESSION_KEY:
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("PGP_PTAG_CT_PK_SESSION_KEY\n");
+ }
+ if (!cbinfo->cryptinfo.secring) {
+ (void) fprintf(io->errs,
+ "pgp_pk_sesskey_cb: bad keyring\n");
+ return (pgp_cb_ret_t)0;
+ }
+ from = 0;
+ cbinfo->cryptinfo.keydata =
+ pgp_getkeybyid(io, cbinfo->cryptinfo.secring,
+ content->pk_sesskey.key_id, &from, NULL);
+ if (!cbinfo->cryptinfo.keydata) {
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return PGP_RELEASE_MEMORY;
+}
+
+/**
+ \ingroup Core_Callbacks
+
+\brief Callback to get secret key, decrypting if necessary.
+
+@verbatim
+ This callback does the following:
+ * finds the session key in the keyring
+ * gets a passphrase if required
+ * decrypts the secret key, if necessary
+ * sets the seckey in the content struct
+@endverbatim
+*/
+
+pgp_cb_ret_t
+pgp_get_seckey_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+ const pgp_seckey_t *secret;
+ const pgp_key_t *pubkey;
+ const pgp_key_t *keypair;
+ unsigned from;
+ pgp_io_t *io;
+ int i;
+
+ io = cbinfo->io;
+ if (pgp_get_debug_level(__FILE__)) {
+ pgp_print_packet(&cbinfo->printstate, pkt);
+ }
+ switch (pkt->tag) {
+ case PGP_GET_SECKEY:
+ /* print key from pubring */
+ from = 0;
+ pubkey = pgp_getkeybyid(io, cbinfo->cryptinfo.pubring,
+ content->get_seckey.pk_sesskey->key_id,
+ &from, NULL);
+ /* validate key from secring */
+ from = 0;
+ cbinfo->cryptinfo.keydata =
+ pgp_getkeybyid(io, cbinfo->cryptinfo.secring,
+ content->get_seckey.pk_sesskey->key_id,
+ &from, NULL);
+ if (!cbinfo->cryptinfo.keydata ||
+ !pgp_is_key_secret(cbinfo->cryptinfo.keydata)) {
+ return (pgp_cb_ret_t)0;
+ }
+ keypair = cbinfo->cryptinfo.keydata;
+ if (pubkey == NULL) {
+ pubkey = keypair;
+ }
+ secret = NULL;
+ cbinfo->gotpass = 0;
+ for (i = 0 ; cbinfo->numtries == -1 || i < cbinfo->numtries ; i++) {
+ /* print out the user id */
+ pgp_print_keydata(io, cbinfo->cryptinfo.pubring, pubkey,
+ "signature ", &pubkey->key.pubkey, 0);
+ /* now decrypt key */
+ secret = pgp_decrypt_seckey(keypair, cbinfo->passfp);
+ if (secret != NULL) {
+ break;
+ }
+ (void) fprintf(io->errs, "Bad passphrase\n");
+ }
+ if (secret == NULL) {
+ (void) fprintf(io->errs, "Exhausted passphrase attempts\n");
+ return (pgp_cb_ret_t)PGP_RELEASE_MEMORY;
+ }
+ cbinfo->gotpass = 1;
+ *content->get_seckey.seckey = secret;
+ break;
+
+ default:
+ break;
+ }
+
+ return PGP_RELEASE_MEMORY;
+}
+
+/**
+ \ingroup HighLevel_Callbacks
+ \brief Callback to use when you need to prompt user for passphrase
+ \param contents
+ \param cbinfo
+*/
+pgp_cb_ret_t
+get_passphrase_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
+{
+ const pgp_contents_t *content = &pkt->u;
+ pgp_io_t *io;
+
+ io = cbinfo->io;
+ if (pgp_get_debug_level(__FILE__)) {
+ pgp_print_packet(&cbinfo->printstate, pkt);
+ }
+ if (cbinfo->cryptinfo.keydata == NULL) {
+ (void) fprintf(io->errs, "get_passphrase_cb: NULL keydata\n");
+ } else {
+ pgp_print_keydata(io, cbinfo->cryptinfo.pubring, cbinfo->cryptinfo.keydata, "signature ",
+ &cbinfo->cryptinfo.keydata->key.pubkey, 0);
+ }
+ switch (pkt->tag) {
+ case PGP_GET_PASSPHRASE:
+ *(content->skey_passphrase.passphrase) =
+ netpgp_strdup(getpass("netpgp passphrase: "));
+ return PGP_KEEP_MEMORY;
+ default:
+ break;
+ }
+ return PGP_RELEASE_MEMORY;
+}
+
+unsigned
+pgp_reader_set_accumulate(pgp_stream_t *stream, unsigned state)
+{
+ return stream->readinfo.accumulate = state;
+}
+
+/**************************************************************************/
+
+static int
+hash_reader(pgp_stream_t *stream, void *dest,
+ size_t length,
+ pgp_error_t **errors,
+ pgp_reader_t *readinfo,
+ pgp_cbdata_t *cbinfo)
+{
+ pgp_hash_t *hash = pgp_reader_get_arg(readinfo);
+ int r;
+
+ r = pgp_stacked_read(stream, dest, length, errors, readinfo, cbinfo);
+ if (r <= 0) {
+ return r;
+ }
+ hash->add(hash, dest, (unsigned)r);
+ return r;
+}
+
+/**
+ \ingroup Internal_Readers_Hash
+ \brief Push hashed data reader on stack
+*/
+void
+pgp_reader_push_hash(pgp_stream_t *stream, pgp_hash_t *hash)
+{
+ if (!hash->init(hash)) {
+ (void) fprintf(stderr, "pgp_reader_push_hash: can't init hash\n");
+ /* just continue and die */
+ /* XXX - agc - no way to return failure */
+ }
+ pgp_reader_push(stream, hash_reader, NULL, hash);
+}
+
+/**
+ \ingroup Internal_Readers_Hash
+ \brief Pop hashed data reader from stack
+*/
+void
+pgp_reader_pop_hash(pgp_stream_t *stream)
+{
+ pgp_reader_pop(stream);
+}
+
+/* read memory from the previously mmap-ed file */
+static int
+mmap_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
+ pgp_reader_t *readinfo, pgp_cbdata_t *cbinfo)
+{
+ mmap_reader_t *mem = pgp_reader_get_arg(readinfo);
+ unsigned n;
+ char *cmem = mem->mem;
+
+ __PGP_USED(errors);
+ __PGP_USED(cbinfo);
+ if (!stream->coalescing && stream->virtualc && stream->virtualoff < stream->virtualc) {
+ n = read_partial_data(stream, dest, length);
+ } else {
+ n = (unsigned)MIN(length, (unsigned)(mem->size - mem->offset));
+ if (n > 0) {
+ (void) memcpy(dest, &cmem[(int)mem->offset], (unsigned)n);
+ mem->offset += n;
+ }
+ }
+ return (int)n;
+}
+
+/* tear down the mmap, close the fd */
+static void
+mmap_destroyer(pgp_reader_t *readinfo)
+{
+ mmap_reader_t *mem = pgp_reader_get_arg(readinfo);
+
+ (void) munmap(mem->mem, (unsigned)mem->size);
+ (void) close(mem->fd);
+ free(pgp_reader_get_arg(readinfo));
+}
+
+/* set up the file to use mmap-ed memory if available, file IO otherwise */
+void
+pgp_reader_set_mmap(pgp_stream_t *stream, int fd)
+{
+ mmap_reader_t *mem;
+ struct stat st;
+
+ if (fstat(fd, &st) != 0) {
+ (void) fprintf(stderr, "pgp_reader_set_mmap: can't fstat\n");
+ } else if ((mem = calloc(1, sizeof(*mem))) == NULL) {
+ (void) fprintf(stderr, "pgp_reader_set_mmap: bad alloc\n");
+ } else {
+ mem->size = (uint64_t)st.st_size;
+ mem->offset = 0;
+ mem->fd = fd;
+ mem->mem = mmap(NULL, (size_t)st.st_size, PROT_READ,
+ MAP_PRIVATE | MAP_FILE, fd, 0);
+ if (mem->mem == MAP_FAILED) {
+ pgp_reader_set(stream, fd_reader, reader_fd_destroyer,
+ mem);
+ } else {
+ pgp_reader_set(stream, mmap_reader, mmap_destroyer,
+ mem);
+ }
+ }
+}
diff --git a/libs/netpgp/src/lib/readerwriter.h b/libs/netpgp/src/lib/readerwriter.h
new file mode 100644
index 00000000..1b990fc9
--- /dev/null
+++ b/libs/netpgp/src/lib/readerwriter.h
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef READERWRITER_H_
+#define READERWRITER_H_
+
+#include "create.h"
+
+#include "memory.h"
+
+/* if this is defined, we'll use mmap in preference to file ops */
+#define USE_MMAP_FOR_FILES 1
+
+void pgp_reader_set_fd(pgp_stream_t *, int);
+void pgp_reader_set_mmap(pgp_stream_t *, int);
+void pgp_reader_set_memory(pgp_stream_t *, const void *, size_t);
+
+/* Do a sum mod 65536 of all bytes read (as needed for secret keys) */
+void pgp_reader_push_sum16(pgp_stream_t *);
+uint16_t pgp_reader_pop_sum16(pgp_stream_t *);
+
+void pgp_reader_push_se_ip_data(pgp_stream_t *, pgp_crypt_t *,
+ pgp_region_t *);
+void pgp_reader_pop_se_ip_data(pgp_stream_t *);
+
+/* */
+unsigned pgp_write_mdc(pgp_output_t *, const uint8_t *);
+unsigned pgp_write_se_ip_pktset(pgp_output_t *, const uint8_t *,
+ const unsigned,
+ pgp_crypt_t *);
+void pgp_push_enc_crypt(pgp_output_t *, pgp_crypt_t *);
+int pgp_push_enc_se_ip(pgp_output_t *, const pgp_key_t *, const char *);
+
+/* Secret Key checksum */
+void pgp_push_checksum_writer(pgp_output_t *, pgp_seckey_t *);
+unsigned pgp_pop_skey_checksum_writer(pgp_output_t *);
+
+
+/* memory writing */
+void pgp_setup_memory_write(pgp_output_t **, pgp_memory_t **, size_t);
+void pgp_teardown_memory_write(pgp_output_t *, pgp_memory_t *);
+
+/* memory reading */
+void pgp_setup_memory_read(pgp_io_t *,
+ pgp_stream_t **,
+ pgp_memory_t *,
+ void *,
+ pgp_cb_ret_t callback(const pgp_packet_t *,
+ pgp_cbdata_t *),
+ unsigned);
+void pgp_teardown_memory_read(pgp_stream_t *, pgp_memory_t *);
+
+/* file writing */
+int pgp_setup_file_write(pgp_output_t **, const char *, unsigned);
+void pgp_teardown_file_write(pgp_output_t *, int);
+
+/* file appending */
+int pgp_setup_file_append(pgp_output_t **, const char *);
+void pgp_teardown_file_append(pgp_output_t *, int);
+
+/* file reading */
+int pgp_setup_file_read(pgp_io_t *,
+ pgp_stream_t **,
+ const char *,
+ void *,
+ pgp_cb_ret_t callback(const pgp_packet_t *,
+ pgp_cbdata_t *),
+ unsigned);
+void pgp_teardown_file_read(pgp_stream_t *, int);
+
+unsigned pgp_reader_set_accumulate(pgp_stream_t *, unsigned);
+
+/* useful callbacks */
+pgp_cb_ret_t pgp_litdata_cb(const pgp_packet_t *, pgp_cbdata_t *);
+pgp_cb_ret_t pgp_pk_sesskey_cb(const pgp_packet_t *, pgp_cbdata_t *);
+pgp_cb_ret_t pgp_get_seckey_cb(const pgp_packet_t *, pgp_cbdata_t *);
+
+int pgp_getpassphrase(void *, char *, size_t);
+
+#endif /* READERWRITER_H_ */
diff --git a/libs/netpgp/src/lib/signature.c b/libs/netpgp/src/lib/signature.c
new file mode 100644
index 00000000..4c16f7d2
--- /dev/null
+++ b/libs/netpgp/src/lib/signature.c
@@ -0,0 +1,1259 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: signature.c,v 1.34 2012/03/05 02:20:18 christos Exp $");
+#endif
+
+#include
+#include
+
+#ifdef HAVE_FCNTL_H
+#include
+#endif
+
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_DSA_H
+#include
+#endif
+
+#include "signature.h"
+#include "crypto.h"
+#include "create.h"
+#include "netpgpsdk.h"
+#include "readerwriter.h"
+#include "validate.h"
+#include "netpgpdefs.h"
+#include "netpgpdigest.h"
+
+
+/** \ingroup Core_Create
+ * needed for signature creation
+ */
+struct pgp_create_sig_t {
+ pgp_hash_t hash;
+ pgp_sig_t sig;
+ pgp_memory_t *mem;
+ pgp_output_t *output; /* how to do the writing */
+ unsigned hashoff; /* hashed count offset */
+ unsigned hashlen;
+ unsigned unhashoff;
+};
+
+/**
+ \ingroup Core_Signature
+ Creates new pgp_create_sig_t
+ \return new pgp_create_sig_t
+ \note It is the caller's responsibility to call pgp_create_sig_delete()
+ \sa pgp_create_sig_delete()
+*/
+pgp_create_sig_t *
+pgp_create_sig_new(void)
+{
+ return calloc(1, sizeof(pgp_create_sig_t));
+}
+
+/**
+ \ingroup Core_Signature
+ Free signature and memory associated with it
+ \param sig struct to free
+ \sa pgp_create_sig_new()
+*/
+void
+pgp_create_sig_delete(pgp_create_sig_t *sig)
+{
+ pgp_output_delete(sig->output);
+ sig->output = NULL;
+ free(sig);
+}
+
+#if 0
+void
+pgp_dump_sig(pgp_sig_t *sig)
+{
+}
+#endif
+
+static uint8_t prefix_md5[] = {
+ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
+};
+
+static uint8_t prefix_sha1[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02,
+ 0x1A, 0x05, 0x00, 0x04, 0x14
+};
+
+static uint8_t prefix_sha256[] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+};
+
+
+/* XXX: both this and verify would be clearer if the signature were */
+/* treated as an MPI. */
+static int
+rsa_sign(pgp_hash_t *hash,
+ const pgp_rsa_pubkey_t *pubrsa,
+ const pgp_rsa_seckey_t *secrsa,
+ pgp_output_t *out)
+{
+ unsigned prefixsize;
+ unsigned expected;
+ unsigned hashsize;
+ unsigned keysize;
+ unsigned n;
+ unsigned t;
+ uint8_t hashbuf[NETPGP_BUFSIZ];
+ uint8_t sigbuf[NETPGP_BUFSIZ];
+ uint8_t *prefix;
+ BIGNUM *bn;
+
+ if (strcmp(hash->name, "SHA1") == 0) {
+ hashsize = PGP_SHA1_HASH_SIZE + sizeof(prefix_sha1);
+ prefix = prefix_sha1;
+ prefixsize = sizeof(prefix_sha1);
+ expected = PGP_SHA1_HASH_SIZE;
+ } else {
+ hashsize = PGP_SHA256_HASH_SIZE + sizeof(prefix_sha256);
+ prefix = prefix_sha256;
+ prefixsize = sizeof(prefix_sha256);
+ expected = PGP_SHA256_HASH_SIZE;
+ }
+ keysize = (BN_num_bits(pubrsa->n) + 7) / 8;
+ if (keysize > sizeof(hashbuf)) {
+ (void) fprintf(stderr, "rsa_sign: keysize too big\n");
+ return 0;
+ }
+ if (10 + hashsize > keysize) {
+ (void) fprintf(stderr, "rsa_sign: hashsize too big\n");
+ return 0;
+ }
+
+ hashbuf[0] = 0;
+ hashbuf[1] = 1;
+ if (pgp_get_debug_level(__FILE__)) {
+ printf("rsa_sign: PS is %d\n", keysize - hashsize - 1 - 2);
+ }
+ for (n = 2; n < keysize - hashsize - 1; ++n) {
+ hashbuf[n] = 0xff;
+ }
+ hashbuf[n++] = 0;
+
+ (void) memcpy(&hashbuf[n], prefix, prefixsize);
+ n += prefixsize;
+ if ((t = hash->finish(hash, &hashbuf[n])) != expected) {
+ (void) fprintf(stderr, "rsa_sign: short %s hash\n", hash->name);
+ return 0;
+ }
+
+ pgp_write(out, &hashbuf[n], 2);
+
+ n += t;
+ if (n != keysize) {
+ (void) fprintf(stderr, "rsa_sign: n != keysize\n");
+ return 0;
+ }
+
+ t = pgp_rsa_private_encrypt(sigbuf, hashbuf, keysize, secrsa, pubrsa);
+ bn = BN_bin2bn(sigbuf, (int)t, NULL);
+ pgp_write_mpi(out, bn);
+ BN_free(bn);
+ return 1;
+}
+
+static int
+dsa_sign(pgp_hash_t *hash,
+ const pgp_dsa_pubkey_t *dsa,
+ const pgp_dsa_seckey_t *sdsa,
+ pgp_output_t *output)
+{
+ unsigned hashsize;
+ unsigned t;
+ uint8_t hashbuf[NETPGP_BUFSIZ];
+ DSA_SIG *dsasig;
+
+ /* hashsize must be "equal in size to the number of bits of q, */
+ /* the group generated by the DSA key's generator value */
+ /* 160/8 = 20 */
+
+ hashsize = 20;
+
+ /* finalise hash */
+ t = hash->finish(hash, &hashbuf[0]);
+ if (t != 20) {
+ (void) fprintf(stderr, "dsa_sign: hashfinish not 20\n");
+ return 0;
+ }
+
+ pgp_write(output, &hashbuf[0], 2);
+
+ /* write signature to buf */
+ dsasig = pgp_dsa_sign(hashbuf, hashsize, sdsa, dsa);
+
+ /* convert and write the sig out to memory */
+ pgp_write_mpi(output, dsasig->r);
+ pgp_write_mpi(output, dsasig->s);
+ DSA_SIG_free(dsasig);
+ return 1;
+}
+
+static unsigned
+rsa_verify(pgp_hash_alg_t type,
+ const uint8_t *hash,
+ size_t hash_length,
+ const pgp_rsa_sig_t *sig,
+ const pgp_rsa_pubkey_t *pubrsa)
+{
+ const uint8_t *prefix;
+ unsigned n;
+ unsigned keysize;
+ unsigned plen;
+ unsigned debug_len_decrypted;
+ uint8_t sigbuf[NETPGP_BUFSIZ];
+ uint8_t hashbuf_from_sig[NETPGP_BUFSIZ];
+
+ plen = 0;
+ prefix = (const uint8_t *) "";
+ keysize = BN_num_bytes(pubrsa->n);
+ /* RSA key can't be bigger than 65535 bits, so... */
+ if (keysize > sizeof(hashbuf_from_sig)) {
+ (void) fprintf(stderr, "rsa_verify: keysize too big\n");
+ return 0;
+ }
+ if ((unsigned) BN_num_bits(sig->sig) > 8 * sizeof(sigbuf)) {
+ (void) fprintf(stderr, "rsa_verify: BN_numbits too big\n");
+ return 0;
+ }
+ BN_bn2bin(sig->sig, sigbuf);
+
+ n = pgp_rsa_public_decrypt(hashbuf_from_sig, sigbuf,
+ (unsigned)(BN_num_bits(sig->sig) + 7) / 8, pubrsa);
+ debug_len_decrypted = n;
+
+ if (n != keysize) {
+ /* obviously, this includes error returns */
+ return 0;
+ }
+
+ /* XXX: why is there a leading 0? The first byte should be 1... */
+ /* XXX: because the decrypt should use keysize and not sigsize? */
+ if (hashbuf_from_sig[0] != 0 || hashbuf_from_sig[1] != 1) {
+ return 0;
+ }
+
+ switch (type) {
+ case PGP_HASH_MD5:
+ prefix = prefix_md5;
+ plen = sizeof(prefix_md5);
+ break;
+ case PGP_HASH_SHA1:
+ prefix = prefix_sha1;
+ plen = sizeof(prefix_sha1);
+ break;
+ case PGP_HASH_SHA256:
+ prefix = prefix_sha256;
+ plen = sizeof(prefix_sha256);
+ break;
+ default:
+ (void) fprintf(stderr, "Unknown hash algorithm: %d\n", type);
+ return 0;
+ }
+
+ if (keysize - plen - hash_length < 10) {
+ return 0;
+ }
+
+ for (n = 2; n < keysize - plen - hash_length - 1; ++n) {
+ if (hashbuf_from_sig[n] != 0xff) {
+ return 0;
+ }
+ }
+
+ if (hashbuf_from_sig[n++] != 0) {
+ return 0;
+ }
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "sig hashbuf", hashbuf_from_sig, debug_len_decrypted);
+ hexdump(stderr, "prefix", prefix, plen);
+ hexdump(stderr, "sig hash", &hashbuf_from_sig[n + plen], hash_length);
+ hexdump(stderr, "input hash", hash, hash_length);
+ }
+ return (memcmp(&hashbuf_from_sig[n], prefix, plen) == 0 &&
+ memcmp(&hashbuf_from_sig[n + plen], hash, hash_length) == 0);
+}
+
+static void
+hash_add_key(pgp_hash_t *hash, const pgp_pubkey_t *key)
+{
+ pgp_memory_t *mem = pgp_memory_new();
+ const unsigned dontmakepacket = 0;
+ size_t len;
+
+ pgp_build_pubkey(mem, key, dontmakepacket);
+ len = pgp_mem_len(mem);
+ pgp_hash_add_int(hash, 0x99, 1);
+ pgp_hash_add_int(hash, (unsigned)len, 2);
+ hash->add(hash, pgp_mem_data(mem), (unsigned)len);
+ pgp_memory_free(mem);
+}
+
+static void
+initialise_hash(pgp_hash_t *hash, const pgp_sig_t *sig)
+{
+ pgp_hash_any(hash, sig->info.hash_alg);
+ if (!hash->init(hash)) {
+ (void) fprintf(stderr,
+ "initialise_hash: bad hash init\n");
+ /* just continue and die */
+ /* XXX - agc - no way to return failure */
+ }
+}
+
+static void
+init_key_sig(pgp_hash_t *hash, const pgp_sig_t *sig,
+ const pgp_pubkey_t *key)
+{
+ initialise_hash(hash, sig);
+ hash_add_key(hash, key);
+}
+
+static void
+hash_add_trailer(pgp_hash_t *hash, const pgp_sig_t *sig,
+ const uint8_t *raw_packet)
+{
+ if (sig->info.version == PGP_V4) {
+ if (raw_packet) {
+ hash->add(hash, raw_packet + sig->v4_hashstart,
+ (unsigned)sig->info.v4_hashlen);
+ }
+ pgp_hash_add_int(hash, (unsigned)sig->info.version, 1);
+ pgp_hash_add_int(hash, 0xff, 1);
+ pgp_hash_add_int(hash, (unsigned)sig->info.v4_hashlen, 4);
+ } else {
+ pgp_hash_add_int(hash, (unsigned)sig->info.type, 1);
+ pgp_hash_add_int(hash, (unsigned)sig->info.birthtime, 4);
+ }
+}
+
+/**
+ \ingroup Core_Signature
+ \brief Checks a signature
+ \param hash Signature Hash to be checked
+ \param length Signature Length
+ \param sig The Signature to be checked
+ \param signer The signer's public key
+ \return 1 if good; else 0
+*/
+unsigned
+pgp_check_sig(const uint8_t *hash, unsigned length,
+ const pgp_sig_t * sig,
+ const pgp_pubkey_t * signer)
+{
+ unsigned ret;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stdout, "hash", hash, length);
+ }
+ ret = 0;
+ switch (sig->info.key_alg) {
+ case PGP_PKA_DSA:
+ ret = pgp_dsa_verify(hash, length, &sig->info.sig.dsa,
+ &signer->key.dsa);
+ break;
+
+ case PGP_PKA_RSA:
+ ret = rsa_verify(sig->info.hash_alg, hash, length,
+ &sig->info.sig.rsa,
+ &signer->key.rsa);
+ break;
+
+ default:
+ (void) fprintf(stderr, "pgp_check_sig: unusual alg\n");
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static unsigned
+hash_and_check_sig(pgp_hash_t *hash,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer)
+{
+ uint8_t hashout[PGP_MAX_HASH_SIZE];
+ unsigned n;
+
+ n = hash->finish(hash, hashout);
+ return pgp_check_sig(hashout, n, sig, signer);
+}
+
+static unsigned
+finalise_sig(pgp_hash_t *hash,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer,
+ const uint8_t *raw_packet)
+{
+ hash_add_trailer(hash, sig, raw_packet);
+ return hash_and_check_sig(hash, sig, signer);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * \brief Verify a certification signature.
+ *
+ * \param key The public key that was signed.
+ * \param id The user ID that was signed
+ * \param sig The signature.
+ * \param signer The public key of the signer.
+ * \param raw_packet The raw signature packet.
+ * \return 1 if OK; else 0
+ */
+unsigned
+pgp_check_useridcert_sig(const pgp_pubkey_t *key,
+ const uint8_t *id,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer,
+ const uint8_t *raw_packet)
+{
+ pgp_hash_t hash;
+ size_t userid_len;
+
+ userid_len = strlen((const char *) id);
+ init_key_sig(&hash, sig, key);
+ if (sig->info.version == PGP_V4) {
+ pgp_hash_add_int(&hash, 0xb4, 1);
+ pgp_hash_add_int(&hash, (unsigned)userid_len, 4);
+ }
+ hash.add(&hash, id, (unsigned)userid_len);
+ return finalise_sig(&hash, sig, signer, raw_packet);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Verify a certification signature.
+ *
+ * \param key The public key that was signed.
+ * \param attribute The user attribute that was signed
+ * \param sig The signature.
+ * \param signer The public key of the signer.
+ * \param raw_packet The raw signature packet.
+ * \return 1 if OK; else 0
+ */
+unsigned
+pgp_check_userattrcert_sig(const pgp_pubkey_t *key,
+ const pgp_data_t *attribute,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer,
+ const uint8_t *raw_packet)
+{
+ pgp_hash_t hash;
+
+ init_key_sig(&hash, sig, key);
+ if (sig->info.version == PGP_V4) {
+ pgp_hash_add_int(&hash, 0xd1, 1);
+ pgp_hash_add_int(&hash, (unsigned)attribute->len, 4);
+ }
+ hash.add(&hash, attribute->contents, (unsigned)attribute->len);
+ return finalise_sig(&hash, sig, signer, raw_packet);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Verify a subkey signature.
+ *
+ * \param key The public key whose subkey was signed.
+ * \param subkey The subkey of the public key that was signed.
+ * \param sig The signature.
+ * \param signer The public key of the signer.
+ * \param raw_packet The raw signature packet.
+ * \return 1 if OK; else 0
+ */
+unsigned
+pgp_check_subkey_sig(const pgp_pubkey_t *key,
+ const pgp_pubkey_t *subkey,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer,
+ const uint8_t *raw_packet)
+{
+ pgp_hash_t hash;
+ unsigned ret;
+
+ init_key_sig(&hash, sig, key);
+ hash_add_key(&hash, subkey);
+ ret = finalise_sig(&hash, sig, signer, raw_packet);
+ return ret;
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Verify a direct signature.
+ *
+ * \param key The public key which was signed.
+ * \param sig The signature.
+ * \param signer The public key of the signer.
+ * \param raw_packet The raw signature packet.
+ * \return 1 if OK; else 0
+ */
+unsigned
+pgp_check_direct_sig(const pgp_pubkey_t *key,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer,
+ const uint8_t *raw_packet)
+{
+ pgp_hash_t hash;
+ unsigned ret;
+
+ init_key_sig(&hash, sig, key);
+ ret = finalise_sig(&hash, sig, signer, raw_packet);
+ return ret;
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Verify a signature on a hash (the hash will have already been fed
+ * the material that was being signed, for example signed cleartext).
+ *
+ * \param hash A hash structure of appropriate type that has been fed
+ * the material to be signed. This MUST NOT have been finalised.
+ * \param sig The signature to be verified.
+ * \param signer The public key of the signer.
+ * \return 1 if OK; else 0
+ */
+unsigned
+pgp_check_hash_sig(pgp_hash_t *hash,
+ const pgp_sig_t *sig,
+ const pgp_pubkey_t *signer)
+{
+ return (sig->info.hash_alg == hash->alg) ?
+ finalise_sig(hash, sig, signer, NULL) :
+ 0;
+}
+
+static void
+start_sig_in_mem(pgp_create_sig_t *sig)
+{
+ /* since this has subpackets and stuff, we have to buffer the whole */
+ /* thing to get counts before writing. */
+ sig->mem = pgp_memory_new();
+ pgp_memory_init(sig->mem, 100);
+ pgp_writer_set_memory(sig->output, sig->mem);
+
+ /* write nearly up to the first subpacket */
+ pgp_write_scalar(sig->output, (unsigned)sig->sig.info.version, 1);
+ pgp_write_scalar(sig->output, (unsigned)sig->sig.info.type, 1);
+ pgp_write_scalar(sig->output, (unsigned)sig->sig.info.key_alg, 1);
+ pgp_write_scalar(sig->output, (unsigned)sig->sig.info.hash_alg, 1);
+
+ /* dummy hashed subpacket count */
+ sig->hashoff = (unsigned)pgp_mem_len(sig->mem);
+ pgp_write_scalar(sig->output, 0, 2);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * pgp_sig_start() creates a V4 public key signature with a SHA1 hash.
+ *
+ * \param sig The signature structure to initialise
+ * \param key The public key to be signed
+ * \param id The user ID being bound to the key
+ * \param type Signature type
+ */
+void
+pgp_sig_start_key_sig(pgp_create_sig_t *sig,
+ const pgp_pubkey_t *key,
+ const uint8_t *id,
+ pgp_sig_type_t type)
+{
+ sig->output = pgp_output_new();
+
+ /* XXX: refactor with check (in several ways - check should
+ * probably use the buffered writer to construct packets
+ * (done), and also should share code for hash calculation) */
+ sig->sig.info.version = PGP_V4;
+ sig->sig.info.hash_alg = PGP_HASH_SHA1;
+ sig->sig.info.key_alg = key->alg;
+ sig->sig.info.type = type;
+ sig->hashlen = (unsigned)-1;
+ init_key_sig(&sig->hash, &sig->sig, key);
+ pgp_hash_add_int(&sig->hash, 0xb4, 1);
+ pgp_hash_add_int(&sig->hash, (unsigned)strlen((const char *) id), 4);
+ sig->hash.add(&sig->hash, id, (unsigned)strlen((const char *) id));
+ start_sig_in_mem(sig);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Create a V4 public key signature over some cleartext.
+ *
+ * \param sig The signature structure to initialise
+ * \param id
+ * \param type
+ * \todo Expand description. Allow other hashes.
+ */
+
+void
+pgp_start_sig(pgp_create_sig_t *sig,
+ const pgp_seckey_t *key,
+ const pgp_hash_alg_t hash,
+ const pgp_sig_type_t type)
+{
+ sig->output = pgp_output_new();
+
+ /* XXX: refactor with check (in several ways - check should
+ * probably use the buffered writer to construct packets
+ * (done), and also should share code for hash calculation) */
+ sig->sig.info.version = PGP_V4;
+ sig->sig.info.key_alg = key->pubkey.alg;
+ sig->sig.info.hash_alg = hash;
+ sig->sig.info.type = type;
+
+ sig->hashlen = (unsigned)-1;
+
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "initialising hash for sig in mem\n");
+ }
+ initialise_hash(&sig->hash, &sig->sig);
+ start_sig_in_mem(sig);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Add plaintext data to a signature-to-be.
+ *
+ * \param sig The signature-to-be.
+ * \param buf The plaintext data.
+ * \param length The amount of plaintext data.
+ */
+void
+pgp_sig_add_data(pgp_create_sig_t *sig, const void *buf, size_t length)
+{
+ sig->hash.add(&sig->hash, buf, (unsigned)length);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Mark the end of the hashed subpackets in the signature
+ *
+ * \param sig
+ */
+
+unsigned
+pgp_end_hashed_subpkts(pgp_create_sig_t *sig)
+{
+ sig->hashlen = (unsigned)(pgp_mem_len(sig->mem) - sig->hashoff - 2);
+ pgp_memory_place_int(sig->mem, sig->hashoff, sig->hashlen, 2);
+ /* dummy unhashed subpacket count */
+ sig->unhashoff = (unsigned)pgp_mem_len(sig->mem);
+ return pgp_write_scalar(sig->output, 0, 2);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Write out a signature
+ *
+ * \param sig
+ * \param key
+ * \param seckey
+ * \param info
+ *
+ */
+
+unsigned
+pgp_write_sig(pgp_output_t *output,
+ pgp_create_sig_t *sig,
+ const pgp_pubkey_t *key,
+ const pgp_seckey_t *seckey)
+{
+ unsigned ret = 0;
+ size_t len = pgp_mem_len(sig->mem);
+
+ /* check key not decrypted */
+ switch (seckey->pubkey.alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (seckey->key.rsa.d == NULL) {
+ (void) fprintf(stderr, "pgp_write_sig: null rsa.d\n");
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_DSA:
+ if (seckey->key.dsa.x == NULL) {
+ (void) fprintf(stderr, "pgp_write_sig: null dsa.x\n");
+ return 0;
+ }
+ break;
+
+ default:
+ (void) fprintf(stderr, "Unsupported algorithm %d\n",
+ seckey->pubkey.alg);
+ return 0;
+ }
+
+ if (sig->hashlen == (unsigned) -1) {
+ (void) fprintf(stderr,
+ "ops_write_sig: bad hashed data len\n");
+ return 0;
+ }
+
+ pgp_memory_place_int(sig->mem, sig->unhashoff,
+ (unsigned)(len - sig->unhashoff - 2), 2);
+
+ /* add the packet from version number to end of hashed subpackets */
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "ops_write_sig: hashed packet info\n");
+ }
+ sig->hash.add(&sig->hash, pgp_mem_data(sig->mem), sig->unhashoff);
+
+ /* add final trailer */
+ pgp_hash_add_int(&sig->hash, (unsigned)sig->sig.info.version, 1);
+ pgp_hash_add_int(&sig->hash, 0xff, 1);
+ /* +6 for version, type, pk alg, hash alg, hashed subpacket length */
+ pgp_hash_add_int(&sig->hash, sig->hashlen + 6, 4);
+
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "ops_write_sig: done writing hashed\n");
+ }
+ /* XXX: technically, we could figure out how big the signature is */
+ /* and write it directly to the output instead of via memory. */
+ switch (seckey->pubkey.alg) {
+ case PGP_PKA_RSA:
+ case PGP_PKA_RSA_ENCRYPT_ONLY:
+ case PGP_PKA_RSA_SIGN_ONLY:
+ if (!rsa_sign(&sig->hash, &key->key.rsa, &seckey->key.rsa,
+ sig->output)) {
+ (void) fprintf(stderr,
+ "pgp_write_sig: rsa_sign failure\n");
+ return 0;
+ }
+ break;
+
+ case PGP_PKA_DSA:
+ if (!dsa_sign(&sig->hash, &key->key.dsa, &seckey->key.dsa,
+ sig->output)) {
+ (void) fprintf(stderr,
+ "pgp_write_sig: dsa_sign failure\n");
+ return 0;
+ }
+ break;
+
+ default:
+ (void) fprintf(stderr, "Unsupported algorithm %d\n",
+ seckey->pubkey.alg);
+ return 0;
+ }
+
+ ret = pgp_write_ptag(output, PGP_PTAG_CT_SIGNATURE);
+ if (ret) {
+ len = pgp_mem_len(sig->mem);
+ ret = pgp_write_length(output, (unsigned)len) &&
+ pgp_write(output, pgp_mem_data(sig->mem), (unsigned)len);
+ }
+ pgp_memory_free(sig->mem);
+
+ if (ret == 0) {
+ PGP_ERROR_1(&output->errors, PGP_E_W, "%s",
+ "Cannot write signature");
+ }
+ return ret;
+}
+
+/* add a time stamp to the output */
+unsigned
+pgp_add_time(pgp_create_sig_t *sig, int64_t when, const char *type)
+{
+ pgp_content_enum tag;
+
+ tag = (strcmp(type, "birth") == 0) ?
+ PGP_PTAG_SS_CREATION_TIME : PGP_PTAG_SS_EXPIRATION_TIME;
+ /* just do 32-bit timestamps for just now - it's in the protocol */
+ return pgp_write_ss_header(sig->output, 5, tag) &&
+ pgp_write_scalar(sig->output, (uint32_t)when, (unsigned)sizeof(uint32_t));
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Adds issuer's key ID to the signature
+ *
+ * \param sig
+ * \param keyid
+ */
+
+unsigned
+pgp_add_issuer_keyid(pgp_create_sig_t *sig,
+ const uint8_t keyid[PGP_KEY_ID_SIZE])
+{
+ return pgp_write_ss_header(sig->output, PGP_KEY_ID_SIZE + 1,
+ PGP_PTAG_SS_ISSUER_KEY_ID) &&
+ pgp_write(sig->output, keyid, PGP_KEY_ID_SIZE);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Adds primary user ID to the signature
+ *
+ * \param sig
+ * \param primary
+ */
+void
+pgp_add_primary_userid(pgp_create_sig_t *sig, unsigned primary)
+{
+ pgp_write_ss_header(sig->output, 2, PGP_PTAG_SS_PRIMARY_USER_ID);
+ pgp_write_scalar(sig->output, primary, 1);
+}
+
+/**
+ * \ingroup Core_Signature
+ *
+ * Get the hash structure in use for the signature.
+ *
+ * \param sig The signature structure.
+ * \return The hash structure.
+ */
+pgp_hash_t *
+pgp_sig_get_hash(pgp_create_sig_t *sig)
+{
+ return &sig->hash;
+}
+
+/* open up an output file */
+static int
+open_output_file(pgp_output_t **output,
+ const char *inname,
+ const char *outname,
+ const char *suffix,
+ const unsigned overwrite)
+{
+ int fd;
+
+ /* setup output file */
+ if (outname) {
+ fd = pgp_setup_file_write(output, outname, overwrite);
+ } else {
+ unsigned flen = (unsigned)(strlen(inname) + 4 + 1);
+ char *f = NULL;
+
+ if ((f = calloc(1, flen)) == NULL) {
+ (void) fprintf(stderr, "open_output_file: bad alloc\n");
+ fd = -1;
+ } else {
+ (void) snprintf(f, flen, "%s.%s", inname, suffix);
+ fd = pgp_setup_file_write(output, f, overwrite);
+ free(f);
+ }
+ }
+ return fd;
+}
+
+/**
+\ingroup HighLevel_Sign
+\brief Sign a file
+\param inname Input filename
+\param outname Output filename. If NULL, a name is constructed from the input filename.
+\param seckey Secret Key to use for signing
+\param armored Write armoured text, if set.
+\param overwrite May overwrite existing file, if set.
+\return 1 if OK; else 0;
+
+*/
+unsigned
+pgp_sign_file(pgp_io_t *io,
+ const char *inname,
+ const char *outname,
+ const pgp_seckey_t *seckey,
+ const char *hashname,
+ const int64_t from,
+ const uint64_t duration,
+ const unsigned armored,
+ const unsigned cleartext,
+ const unsigned overwrite)
+{
+ pgp_create_sig_t *sig;
+ pgp_sig_type_t sig_type;
+ pgp_hash_alg_t hash_alg;
+ pgp_memory_t *infile;
+ pgp_output_t *output;
+ pgp_hash_t *hash;
+ unsigned ret;
+ uint8_t keyid[PGP_KEY_ID_SIZE];
+ int fd_out;
+
+ sig = NULL;
+ sig_type = PGP_SIG_BINARY;
+ infile = NULL;
+ output = NULL;
+ hash = NULL;
+ fd_out = 0;
+
+ /* find the hash algorithm */
+ hash_alg = pgp_str_to_hash_alg(hashname);
+ if (hash_alg == PGP_HASH_UNKNOWN) {
+ (void) fprintf(io->errs,
+ "pgp_sign_file: unknown hash algorithm: \"%s\"\n",
+ hashname);
+ return 0;
+ }
+
+ /* read input file into buf */
+ infile = pgp_memory_new();
+ if (!pgp_mem_readfile(infile, inname)) {
+ return 0;
+ }
+
+ /* setup output file */
+ fd_out = open_output_file(&output, inname, outname,
+ (armored) ? "asc" : "gpg", overwrite);
+ if (fd_out < 0) {
+ pgp_memory_free(infile);
+ return 0;
+ }
+
+ /* set up signature */
+ sig = pgp_create_sig_new();
+ if (!sig) {
+ pgp_memory_free(infile);
+ pgp_teardown_file_write(output, fd_out);
+ return 0;
+ }
+
+ pgp_start_sig(sig, seckey, hash_alg, sig_type);
+
+ if (cleartext) {
+ if (pgp_writer_push_clearsigned(output, sig) != 1) {
+ return 0;
+ }
+
+ /* Do the signing */
+ pgp_write(output, pgp_mem_data(infile), (unsigned)pgp_mem_len(infile));
+ pgp_memory_free(infile);
+
+ /* add signature with subpackets: */
+ /* - creation time */
+ /* - key id */
+ ret = pgp_writer_use_armored_sig(output) &&
+ pgp_add_time(sig, (int64_t)from, "birth") &&
+ pgp_add_time(sig, (int64_t)duration, "expiration");
+ if (ret == 0) {
+ pgp_teardown_file_write(output, fd_out);
+ return 0;
+ }
+
+ pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg);
+ ret = pgp_add_issuer_keyid(sig, keyid) &&
+ pgp_end_hashed_subpkts(sig) &&
+ pgp_write_sig(output, sig, &seckey->pubkey, seckey);
+
+ pgp_teardown_file_write(output, fd_out);
+
+ if (ret == 0) {
+ PGP_ERROR_1(&output->errors, PGP_E_W, "%s",
+ "Cannot sign file as cleartext");
+ }
+ } else {
+ /* set armoured/not armoured here */
+ if (armored) {
+ pgp_writer_push_armor_msg(output);
+ }
+
+ /* write one_pass_sig */
+ pgp_write_one_pass_sig(output, seckey, hash_alg, sig_type);
+
+ /* hash file contents */
+ hash = pgp_sig_get_hash(sig);
+ hash->add(hash, pgp_mem_data(infile), (unsigned)pgp_mem_len(infile));
+
+#if 1
+ /* output file contents as Literal Data packet */
+ pgp_write_litdata(output, pgp_mem_data(infile),
+ (const int)pgp_mem_len(infile),
+ PGP_LDT_BINARY);
+#else
+ /* XXX - agc - sync with writer.c 1094 for ops_writez */
+ pgp_setup_memory_write(&litoutput, &litmem, bufsz);
+ pgp_setup_memory_write(&zoutput, &zmem, bufsz);
+ pgp_write_litdata(litoutput,
+ pgp_mem_data(pgp_mem_data(infile),
+ (const int)pgp_mem_len(infile), PGP_LDT_BINARY);
+ pgp_writez(zoutput, pgp_mem_data(litmem), pgp_mem_len(litmem));
+#endif
+
+ /* add creation time to signature */
+ pgp_add_time(sig, (int64_t)from, "birth");
+ pgp_add_time(sig, (int64_t)duration, "expiration");
+ /* add key id to signature */
+ pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg);
+ pgp_add_issuer_keyid(sig, keyid);
+ pgp_end_hashed_subpkts(sig);
+ pgp_write_sig(output, sig, &seckey->pubkey, seckey);
+
+ /* tidy up */
+ pgp_teardown_file_write(output, fd_out);
+
+ pgp_create_sig_delete(sig);
+ pgp_memory_free(infile);
+
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/**
+\ingroup HighLevel_Sign
+\brief Signs a buffer
+\param input Input text to be signed
+\param input_len Length of input text
+\param sig_type Signature type
+\param seckey Secret Key
+\param armored Write armoured text, if set
+\return New pgp_memory_t struct containing signed text
+\note It is the caller's responsibility to call pgp_memory_free(me)
+
+*/
+pgp_memory_t *
+pgp_sign_buf(pgp_io_t *io,
+ const void *input,
+ const size_t insize,
+ const pgp_seckey_t *seckey,
+ const int64_t from,
+ const uint64_t duration,
+ const char *hashname,
+ const unsigned armored,
+ const unsigned cleartext)
+{
+ pgp_litdata_enum ld_type;
+ pgp_create_sig_t *sig;
+ pgp_sig_type_t sig_type;
+ pgp_hash_alg_t hash_alg;
+ pgp_output_t *output;
+ pgp_memory_t *mem;
+ uint8_t keyid[PGP_KEY_ID_SIZE];
+ pgp_hash_t *hash;
+ unsigned ret;
+
+ sig = NULL;
+ sig_type = PGP_SIG_BINARY;
+ output = NULL;
+ mem = pgp_memory_new();
+ hash = NULL;
+ ret = 0;
+
+ hash_alg = pgp_str_to_hash_alg(hashname);
+ if (hash_alg == PGP_HASH_UNKNOWN) {
+ (void) fprintf(io->errs,
+ "pgp_sign_buf: unknown hash algorithm: \"%s\"\n",
+ hashname);
+ return NULL;
+ }
+
+ /* setup literal data packet type */
+ ld_type = (cleartext) ? PGP_LDT_TEXT : PGP_LDT_BINARY;
+
+ if (input == NULL) {
+ (void) fprintf(io->errs,
+ "pgp_sign_buf: null input\n");
+ return NULL;
+ }
+
+ /* set up signature */
+ if ((sig = pgp_create_sig_new()) == NULL) {
+ return NULL;
+ }
+ pgp_start_sig(sig, seckey, hash_alg, sig_type);
+
+ /* setup writer */
+ pgp_setup_memory_write(&output, &mem, insize);
+
+ if (cleartext) {
+ /* Do the signing */
+ /* add signature with subpackets: */
+ /* - creation time */
+ /* - key id */
+ ret = pgp_writer_push_clearsigned(output, sig) &&
+ pgp_write(output, input, (unsigned)insize) &&
+ pgp_writer_use_armored_sig(output) &&
+ pgp_add_time(sig, from, "birth") &&
+ pgp_add_time(sig, (int64_t)duration, "expiration");
+ if (ret == 0) {
+ return NULL;
+ }
+ pgp_output_delete(output);
+ } else {
+ /* set armoured/not armoured here */
+ if (armored) {
+ pgp_writer_push_armor_msg(output);
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(io->errs, "** Writing out one pass sig\n");
+ }
+ /* write one_pass_sig */
+ pgp_write_one_pass_sig(output, seckey, hash_alg, sig_type);
+
+ /* hash memory */
+ hash = pgp_sig_get_hash(sig);
+ hash->add(hash, input, (unsigned)insize);
+
+ /* output file contents as Literal Data packet */
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(stderr, "** Writing out data now\n");
+ }
+ pgp_write_litdata(output, input, (const int)insize, ld_type);
+ if (pgp_get_debug_level(__FILE__)) {
+ fprintf(stderr, "** After Writing out data now\n");
+ }
+
+ /* add creation time to signature */
+ pgp_add_time(sig, from, "birth");
+ pgp_add_time(sig, (int64_t)duration, "expiration");
+ /* add key id to signature */
+ pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg);
+ pgp_add_issuer_keyid(sig, keyid);
+ pgp_end_hashed_subpkts(sig);
+
+ /* write out sig */
+ pgp_write_sig(output, sig, &seckey->pubkey, seckey);
+
+ /* tidy up */
+ pgp_writer_close(output);
+ pgp_create_sig_delete(sig);
+ }
+ return mem;
+}
+
+/* sign a file, and put the signature in a separate file */
+int
+pgp_sign_detached(pgp_io_t *io,
+ const char *f,
+ char *sigfile,
+ pgp_seckey_t *seckey,
+ const char *hash,
+ const int64_t from,
+ const uint64_t duration,
+ const unsigned armored, const unsigned overwrite)
+{
+ pgp_create_sig_t *sig;
+ pgp_hash_alg_t hash_alg;
+ pgp_output_t *output;
+ pgp_memory_t *mem;
+ uint8_t keyid[PGP_KEY_ID_SIZE];
+ int fd;
+
+ /* find out which hash algorithm to use */
+ hash_alg = pgp_str_to_hash_alg(hash);
+ if (hash_alg == PGP_HASH_UNKNOWN) {
+ (void) fprintf(io->errs,"Unknown hash algorithm: %s\n", hash);
+ return 0;
+ }
+
+ /* setup output file */
+ fd = open_output_file(&output, f, sigfile,
+ (armored) ? "asc" : "sig", overwrite);
+ if (fd < 0) {
+ (void) fprintf(io->errs,"Can't open output file: %s\n", f);
+ return 0;
+ }
+
+ /* create a new signature */
+ sig = pgp_create_sig_new();
+ pgp_start_sig(sig, seckey, hash_alg, PGP_SIG_BINARY);
+
+ /* read the contents of 'f', and add that to the signature */
+ mem = pgp_memory_new();
+ if (!pgp_mem_readfile(mem, f)) {
+ pgp_teardown_file_write(output, fd);
+ return 0;
+ }
+ /* set armoured/not armoured here */
+ if (armored) {
+ pgp_writer_push_armor_msg(output);
+ }
+ pgp_sig_add_data(sig, pgp_mem_data(mem), pgp_mem_len(mem));
+ pgp_memory_free(mem);
+
+ /* calculate the signature */
+ pgp_add_time(sig, from, "birth");
+ pgp_add_time(sig, (int64_t)duration, "expiration");
+ pgp_keyid(keyid, sizeof(keyid), &seckey->pubkey, hash_alg);
+ pgp_add_issuer_keyid(sig, keyid);
+ pgp_end_hashed_subpkts(sig);
+ pgp_write_sig(output, sig, &seckey->pubkey, seckey);
+ pgp_teardown_file_write(output, fd);
+ pgp_seckey_free(seckey);
+
+ return 1;
+}
diff --git a/libs/netpgp/src/lib/signature.h b/libs/netpgp/src/lib/signature.h
new file mode 100644
index 00000000..9e691ddd
--- /dev/null
+++ b/libs/netpgp/src/lib/signature.h
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** \file
+ */
+
+#ifndef SIGNATURE_H_
+#define SIGNATURE_H_
+
+#include
+
+#include
+
+#include "packet.h"
+#include "create.h"
+#include "memory.h"
+
+typedef struct pgp_create_sig_t pgp_create_sig_t;
+
+pgp_create_sig_t *pgp_create_sig_new(void);
+void pgp_create_sig_delete(pgp_create_sig_t *);
+
+unsigned pgp_check_useridcert_sig(const pgp_pubkey_t *,
+ const uint8_t *,
+ const pgp_sig_t *,
+ const pgp_pubkey_t *,
+ const uint8_t *);
+unsigned pgp_check_userattrcert_sig(const pgp_pubkey_t *,
+ const pgp_data_t *,
+ const pgp_sig_t *,
+ const pgp_pubkey_t *,
+ const uint8_t *);
+unsigned pgp_check_subkey_sig(const pgp_pubkey_t *,
+ const pgp_pubkey_t *,
+ const pgp_sig_t *,
+ const pgp_pubkey_t *,
+ const uint8_t *);
+unsigned pgp_check_direct_sig(const pgp_pubkey_t *,
+ const pgp_sig_t *,
+ const pgp_pubkey_t *,
+ const uint8_t *);
+unsigned pgp_check_hash_sig(pgp_hash_t *,
+ const pgp_sig_t *,
+ const pgp_pubkey_t *);
+void pgp_sig_start_key_sig(pgp_create_sig_t *,
+ const pgp_pubkey_t *,
+ const uint8_t *,
+ pgp_sig_type_t);
+void pgp_start_sig(pgp_create_sig_t *,
+ const pgp_seckey_t *,
+ const pgp_hash_alg_t,
+ const pgp_sig_type_t);
+
+void pgp_sig_add_data(pgp_create_sig_t *, const void *, size_t);
+pgp_hash_t *pgp_sig_get_hash(pgp_create_sig_t *);
+unsigned pgp_end_hashed_subpkts(pgp_create_sig_t *);
+unsigned pgp_write_sig(pgp_output_t *, pgp_create_sig_t *,
+ const pgp_pubkey_t *, const pgp_seckey_t *);
+unsigned pgp_add_time(pgp_create_sig_t *, int64_t, const char *);
+unsigned pgp_add_issuer_keyid(pgp_create_sig_t *,
+ const uint8_t *);
+void pgp_add_primary_userid(pgp_create_sig_t *, unsigned);
+
+/* Standard Interface */
+unsigned pgp_sign_file(pgp_io_t *,
+ const char *,
+ const char *,
+ const pgp_seckey_t *,
+ const char *,
+ const int64_t,
+ const uint64_t,
+ const unsigned,
+ const unsigned,
+ const unsigned);
+
+int pgp_sign_detached(pgp_io_t *,
+ const char *,
+ char *,
+ pgp_seckey_t *,
+ const char *,
+ const int64_t,
+ const uint64_t,
+ const unsigned,
+ const unsigned);
+
+/* armoured stuff */
+unsigned pgp_crc24(unsigned, uint8_t);
+
+void pgp_reader_push_dearmour(pgp_stream_t *);
+
+void pgp_reader_pop_dearmour(pgp_stream_t *);
+unsigned pgp_writer_push_clearsigned(pgp_output_t *, pgp_create_sig_t *);
+void pgp_writer_push_armor_msg(pgp_output_t *);
+
+typedef enum {
+ PGP_PGP_MESSAGE = 1,
+ PGP_PGP_PUBLIC_KEY_BLOCK,
+ PGP_PGP_PRIVATE_KEY_BLOCK,
+ PGP_PGP_MULTIPART_MESSAGE_PART_X_OF_Y,
+ PGP_PGP_MULTIPART_MESSAGE_PART_X,
+ PGP_PGP_SIGNATURE
+} pgp_armor_type_t;
+
+#define CRC24_INIT 0xb704ceL
+
+unsigned pgp_writer_use_armored_sig(pgp_output_t *);
+
+void pgp_writer_push_armoured(pgp_output_t *, pgp_armor_type_t);
+
+pgp_memory_t *pgp_sign_buf(pgp_io_t *,
+ const void *,
+ const size_t,
+ const pgp_seckey_t *,
+ const int64_t,
+ const uint64_t,
+ const char *,
+ const unsigned,
+ const unsigned);
+
+unsigned pgp_keyring_read_from_mem(pgp_io_t *,
+ pgp_keyring_t *,
+ const unsigned,
+ pgp_memory_t *);
+
+#endif /* SIGNATURE_H_ */
diff --git a/libs/netpgp/src/lib/ssh2pgp.c b/libs/netpgp/src/lib/ssh2pgp.c
new file mode 100644
index 00000000..8aea0d06
--- /dev/null
+++ b/libs/netpgp/src/lib/ssh2pgp.c
@@ -0,0 +1,473 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include
+#endif
+
+#ifdef HAVE_OPENSSL_CAST_H
+#include
+#endif
+
+#include
+
+#include "bufgap.h"
+
+#include "packet-parse.h"
+#include "netpgpdefs.h"
+#include "netpgpsdk.h"
+#include "crypto.h"
+#include "netpgpdigest.h"
+#include "ssh2pgp.h"
+
+/* structure for earching for constant strings */
+typedef struct str_t {
+ const char *s; /* string */
+ size_t len; /* its length */
+ int type; /* return type */
+} str_t;
+
+#ifndef USE_ARG
+#define USE_ARG(x) /*LINTED*/(void)&x
+#endif
+
+static const uint8_t base64s[] =
+/* 000 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 016 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 032 */ "\0\0\0\0\0\0\0\0\0\0\0?\0\0\0@"
+/* 048 */ "56789:;<=>\0\0\0\0\0\0"
+/* 064 */ "\0\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"
+/* 080 */ "\20\21\22\23\24\25\26\27\30\31\32\0\0\0\0\0"
+/* 096 */ "\0\33\34\35\36\37 !\"#$%&'()"
+/* 112 */ "*+,-./01234\0\0\0\0\0"
+/* 128 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 144 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 160 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 176 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 192 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 208 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 224 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+/* 240 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+
+/* short function to decode from base64 */
+/* inspired by an ancient copy of b64.c, then rewritten, the bugs are all mine */
+static int
+frombase64(char *dst, const char *src, size_t size, int flag)
+{
+ uint8_t out[3];
+ uint8_t in[4];
+ uint8_t b;
+ size_t srcc;
+ int dstc;
+ int gotc;
+ int i;
+
+ USE_ARG(flag);
+ for (dstc = 0, srcc = 0 ; srcc < size; ) {
+ for (gotc = 0, i = 0; i < 4 && srcc < size; i++) {
+ for (b = 0x0; srcc < size && b == 0x0 ; ) {
+ b = base64s[(unsigned)src[srcc++]];
+ }
+ if (srcc < size) {
+ gotc += 1;
+ if (b) {
+ in[i] = (uint8_t)(b - 1);
+ }
+ } else {
+ in[i] = 0x0;
+ }
+ }
+ if (gotc) {
+ out[0] = (uint8_t)((unsigned)in[0] << 2 |
+ (unsigned)in[1] >> 4);
+ out[1] = (uint8_t)((unsigned)in[1] << 4 |
+ (unsigned)in[2] >> 2);
+ out[2] = (uint8_t)(((in[2] << 6) & 0xc0) | in[3]);
+ for (i = 0; i < gotc - 1; i++) {
+ *dst++ = out[i];
+ }
+ dstc += gotc - 1;
+ }
+ }
+ return dstc;
+}
+
+/* get a bignum from the buffer gap */
+static BIGNUM *
+getbignum(bufgap_t *bg, char *buf, const char *header)
+{
+ uint32_t len;
+ BIGNUM *bignum;
+
+ (void) bufgap_getbin(bg, &len, sizeof(len));
+ len = ntohl(len);
+ (void) bufgap_seek(bg, sizeof(len), BGFromHere, BGByte);
+ (void) bufgap_getbin(bg, buf, len);
+ bignum = BN_bin2bn((const uint8_t *)buf, (int)len, NULL);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, header, (const uint8_t *)(void *)buf, len);
+ }
+ (void) bufgap_seek(bg, len, BGFromHere, BGByte);
+ return bignum;
+}
+
+#if 0
+static int
+putbignum(bufgap_t *bg, BIGNUM *bignum)
+{
+ uint32_t len;
+
+ len = BN_num_bytes(bignum);
+ (void) bufgap_insert(bg, &len, sizeof(len));
+ (void) bufgap_insert(bg, buf, len);
+ bignum = BN_bin2bn((const uint8_t *)buf, (int)len, NULL);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, header, buf, (int)len);
+ }
+ (void) bufgap_seek(bg, len, BGFromHere, BGByte);
+ return bignum;
+}
+#endif
+
+static str_t pkatypes[] = {
+ { "ssh-rsa", 7, PGP_PKA_RSA },
+ { "ssh-dss", 7, PGP_PKA_DSA },
+ { "ssh-dsa", 7, PGP_PKA_DSA },
+ { NULL, 0, 0 }
+};
+
+/* look for a string in the given array */
+static int
+findstr(str_t *array, const char *name)
+{
+ str_t *sp;
+
+ for (sp = array ; sp->s ; sp++) {
+ if (strncmp(name, sp->s, sp->len) == 0) {
+ return sp->type;
+ }
+ }
+ return -1;
+}
+
+/* convert an ssh (host) pubkey to a pgp pubkey */
+int
+pgp_ssh2pubkey(pgp_io_t *io, const char *f, pgp_key_t *key, pgp_hash_alg_t hashtype)
+{
+ pgp_pubkey_t *pubkey;
+ struct stat st;
+ bufgap_t bg;
+ uint32_t len;
+ int64_t off;
+ uint8_t *userid;
+ char hostname[256];
+ char owner[256];
+ char *space;
+ char *buf;
+ char *bin;
+ int ok;
+ int cc;
+
+ (void) memset(&bg, 0x0, sizeof(bg));
+ if (!bufgap_open(&bg, f)) {
+ (void) fprintf(stderr, "pgp_ssh2pubkey: can't open '%s'\n", f);
+ return 0;
+ }
+ (void)stat(f, &st);
+ if ((buf = calloc(1, (size_t)st.st_size)) == NULL) {
+ (void) fprintf(stderr, "can't calloc %zu bytes for '%s'\n", (size_t)st.st_size, f);
+ bufgap_close(&bg);
+ return 0;
+ }
+ if ((bin = calloc(1, (size_t)st.st_size)) == NULL) {
+ (void) fprintf(stderr, "can't calloc %zu bytes for '%s'\n", (size_t)st.st_size, f);
+ (void) free(buf);
+ bufgap_close(&bg);
+ return 0;
+ }
+
+ /* move past ascii type of key */
+ while (bufgap_peek(&bg, 0) != ' ') {
+ bufgap_seek(&bg, 1, BGFromHere, BGByte);
+ }
+ bufgap_seek(&bg, 1, BGFromHere, BGByte);
+ off = bufgap_tell(&bg, BGFromBOF, BGByte);
+
+ if (bufgap_size(&bg, BGByte) - off < 10) {
+ (void) fprintf(stderr, "bad key file '%s'\n", f);
+ (void) free(buf);
+ bufgap_close(&bg);
+ return 0;
+ }
+
+ /* convert from base64 to binary */
+ cc = bufgap_getbin(&bg, buf, (size_t)bg.bcc);
+ if ((space = strchr(buf, ' ')) != NULL) {
+ cc = (int)(space - buf);
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, NULL, (const uint8_t *)(const void *)buf, (size_t)cc);
+ }
+ cc = frombase64(bin, buf, (size_t)cc, 0);
+ if (pgp_get_debug_level(__FILE__)) {
+ hexdump(stderr, "decoded base64:", (const uint8_t *)(const void *)bin, (size_t)cc);
+ }
+ bufgap_delete(&bg, (uint64_t)bufgap_tell(&bg, BGFromEOF, BGByte));
+ bufgap_insert(&bg, bin, cc);
+ bufgap_seek(&bg, off, BGFromBOF, BGByte);
+
+ /* get the type of key */
+ (void) bufgap_getbin(&bg, &len, sizeof(len));
+ len = ntohl(len);
+ (void) bufgap_seek(&bg, sizeof(len), BGFromHere, BGByte);
+ (void) bufgap_getbin(&bg, buf, len);
+ (void) bufgap_seek(&bg, len, BGFromHere, BGByte);
+
+ (void) memset(key, 0x0, sizeof(*key));
+ pubkey = &key->key.seckey.pubkey;
+ pubkey->version = PGP_V4;
+ pubkey->birthtime = 0;
+ /* get key type */
+ ok = 1;
+ switch (pubkey->alg = findstr(pkatypes, buf)) {
+ case PGP_PKA_RSA:
+ /* get the 'e' param of the key */
+ pubkey->key.rsa.e = getbignum(&bg, buf, "RSA E");
+ /* get the 'n' param of the key */
+ pubkey->key.rsa.n = getbignum(&bg, buf, "RSA N");
+ break;
+ case PGP_PKA_DSA:
+ /* get the 'p' param of the key */
+ pubkey->key.dsa.p = getbignum(&bg, buf, "DSA P");
+ /* get the 'q' param of the key */
+ pubkey->key.dsa.q = getbignum(&bg, buf, "DSA Q");
+ /* get the 'g' param of the key */
+ pubkey->key.dsa.g = getbignum(&bg, buf, "DSA G");
+ /* get the 'y' param of the key */
+ pubkey->key.dsa.y = getbignum(&bg, buf, "DSA Y");
+ break;
+ default:
+ (void) fprintf(stderr, "Unrecognised pubkey type %d for '%s'\n",
+ pubkey->alg, f);
+ ok = 0;
+ break;
+ }
+
+ /* check for stragglers */
+ if (ok && bufgap_tell(&bg, BGFromEOF, BGByte) > 0) {
+ printf("%"PRIi64" bytes left\n", bufgap_tell(&bg, BGFromEOF, BGByte));
+ printf("[%s]\n", bufgap_getstr(&bg));
+ ok = 0;
+ }
+ if (ok) {
+ (void) memset(&userid, 0x0, sizeof(userid));
+ (void) gethostname(hostname, sizeof(hostname));
+ if (strlen(space + 1) - 1 == 0) {
+ (void) snprintf(owner, sizeof(owner), "",
+ hostname);
+ } else {
+ (void) snprintf(owner, sizeof(owner), "<%.*s>",
+ (int)strlen(space + 1) - 1,
+ space + 1);
+ }
+ (void) pgp_asprintf((char **)(void *)&userid,
+ "%s (%s) %s",
+ hostname,
+ f,
+ owner);
+ pgp_keyid(key->sigid, sizeof(key->sigid), pubkey, hashtype);
+ pgp_add_userid(key, userid);
+ pgp_fingerprint(&key->sigfingerprint, pubkey, hashtype);
+ free(userid);
+ if (pgp_get_debug_level(__FILE__)) {
+ /*pgp_print_keydata(io, keyring, key, "pub", pubkey, 0);*/
+ __PGP_USED(io); /* XXX */
+ }
+ }
+ (void) free(bin);
+ (void) free(buf);
+ bufgap_close(&bg);
+ return ok;
+}
+
+/* convert an ssh (host) seckey to a pgp seckey */
+int
+pgp_ssh2seckey(pgp_io_t *io, const char *f, pgp_key_t *key, pgp_pubkey_t *pubkey, pgp_hash_alg_t hashtype)
+{
+ pgp_crypt_t crypted;
+ pgp_hash_t hash;
+ unsigned done = 0;
+ unsigned i = 0;
+ uint8_t sesskey[CAST_KEY_LENGTH];
+ uint8_t hashed[PGP_SHA1_HASH_SIZE];
+ BIGNUM *tmp;
+
+ __PGP_USED(io);
+ /* XXX - check for rsa/dsa */
+ if (!openssl_read_pem_seckey(f, key, "ssh-rsa", 0)) {
+ return 0;
+ }
+ if (pgp_get_debug_level(__FILE__)) {
+ /*pgp_print_keydata(io, key, "sec", &key->key.seckey.pubkey, 0);*/
+ /* XXX */
+ }
+ /* let's add some sane defaults */
+ (void) memcpy(&key->key.seckey.pubkey, pubkey, sizeof(*pubkey));
+ key->key.seckey.s2k_usage = PGP_S2KU_ENCRYPTED_AND_HASHED;
+ key->key.seckey.alg = PGP_SA_CAST5;
+ key->key.seckey.s2k_specifier = PGP_S2KS_SALTED;
+ key->key.seckey.hash_alg = PGP_HASH_SHA1;
+ if (key->key.seckey.pubkey.alg == PGP_PKA_RSA) {
+ /* openssh and openssl have p and q swapped */
+ tmp = key->key.seckey.key.rsa.p;
+ key->key.seckey.key.rsa.p = key->key.seckey.key.rsa.q;
+ key->key.seckey.key.rsa.q = tmp;
+ }
+ for (done = 0, i = 0; done < CAST_KEY_LENGTH; i++) {
+ unsigned j;
+ uint8_t zero = 0;
+ int needed;
+ int size;
+
+ needed = CAST_KEY_LENGTH - done;
+ size = MIN(needed, PGP_SHA1_HASH_SIZE);
+
+ pgp_hash_any(&hash, key->key.seckey.hash_alg);
+ if (!hash.init(&hash)) {
+ (void) fprintf(stderr, "write_seckey_body: bad alloc\n");
+ return 0;
+ }
+
+ /* preload if iterating */
+ for (j = 0; j < i; j++) {
+ /*
+ * Coverity shows a DEADCODE error on this
+ * line. This is expected since the hardcoded
+ * use of SHA1 and CAST5 means that it will
+ * not used. This will change however when
+ * other algorithms are supported.
+ */
+ hash.add(&hash, &zero, 1);
+ }
+
+ if (key->key.seckey.s2k_specifier == PGP_S2KS_SALTED) {
+ hash.add(&hash, key->key.seckey.salt, PGP_SALT_SIZE);
+ }
+ hash.finish(&hash, hashed);
+
+ /*
+ * if more in hash than is needed by session key, use
+ * the leftmost octets
+ */
+ (void) memcpy(&sesskey[i * PGP_SHA1_HASH_SIZE],
+ hashed, (unsigned)size);
+ done += (unsigned)size;
+ if (done > CAST_KEY_LENGTH) {
+ (void) fprintf(stderr,
+ "write_seckey_body: short add\n");
+ return 0;
+ }
+ }
+ pgp_crypt_any(&crypted, key->key.seckey.alg);
+ crypted.set_iv(&crypted, key->key.seckey.iv);
+ crypted.set_crypt_key(&crypted, sesskey);
+ pgp_encrypt_init(&crypted);
+ key->key.seckey.pubkey.alg = PGP_PKA_RSA;
+ pgp_fingerprint(&key->sigfingerprint, pubkey, hashtype);
+ pgp_keyid(key->sigid, sizeof(key->sigid), pubkey, hashtype);
+ return 1;
+}
+
+/* read a key from the ssh file, and add it to a keyring */
+int
+pgp_ssh2_readkeys(pgp_io_t *io, pgp_keyring_t *pubring,
+ pgp_keyring_t *secring, const char *pubfile,
+ const char *secfile, unsigned hashtype)
+{
+ pgp_key_t *pubkey;
+ pgp_key_t *seckey;
+ pgp_key_t key;
+
+ pubkey = NULL;
+ (void) memset(&key, 0x0, sizeof(key));
+ if (pubfile) {
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(io->errs, "pgp_ssh2_readkeys: pubfile '%s'\n", pubfile);
+ }
+ if (!pgp_ssh2pubkey(io, pubfile, &key, (pgp_hash_alg_t)hashtype)) {
+ (void) fprintf(io->errs, "pgp_ssh2_readkeys: can't read pubkeys '%s'\n", pubfile);
+ return 0;
+ }
+ EXPAND_ARRAY(pubring, key);
+ pubkey = &pubring->keys[pubring->keyc++];
+ (void) memcpy(pubkey, &key, sizeof(key));
+ pubkey->type = PGP_PTAG_CT_PUBLIC_KEY;
+ }
+ if (secfile) {
+ if (pgp_get_debug_level(__FILE__)) {
+ (void) fprintf(io->errs, "pgp_ssh2_readkeys: secfile '%s'\n", secfile);
+ }
+ if (pubkey == NULL) {
+ pubkey = &pubring->keys[0];
+ }
+ if (!pgp_ssh2seckey(io, secfile, &key, &pubkey->key.pubkey, (pgp_hash_alg_t)hashtype)) {
+ (void) fprintf(io->errs, "pgp_ssh2_readkeys: can't read seckeys '%s'\n", secfile);
+ return 0;
+ }
+ EXPAND_ARRAY(secring, key);
+ seckey = &secring->keys[secring->keyc++];
+ (void) memcpy(seckey, &key, sizeof(key));
+ seckey->type = PGP_PTAG_CT_SECRET_KEY;
+ }
+ return 1;
+}
diff --git a/libs/netpgp/src/lib/ssh2pgp.h b/libs/netpgp/src/lib/ssh2pgp.h
new file mode 100644
index 00000000..c1186d79
--- /dev/null
+++ b/libs/netpgp/src/lib/ssh2pgp.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SSH2PGP_H_
+#define SSH2PGP_H_
+
+#include "keyring.h"
+#include "types.h"
+
+int pgp_ssh2pubkey(pgp_io_t *, const char *, pgp_key_t *, pgp_hash_alg_t);
+int pgp_ssh2seckey(pgp_io_t *, const char *, pgp_key_t *, pgp_pubkey_t *, pgp_hash_alg_t);
+
+int pgp_ssh2_readkeys(pgp_io_t *, pgp_keyring_t *, pgp_keyring_t *,
+ const char *, const char *, unsigned);
+
+#endif
diff --git a/libs/netpgp/src/lib/symmetric.c b/libs/netpgp/src/lib/symmetric.c
new file mode 100644
index 00000000..f7a44502
--- /dev/null
+++ b/libs/netpgp/src/lib/symmetric.c
@@ -0,0 +1,802 @@
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Alistair Crooks (agc@NetBSD.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
+ * All rights reserved.
+ * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
+ * their moral rights under the UK Copyright Design and Patents Act 1988 to
+ * be recorded as the authors of this copyright work.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_CDEFS_H
+#include
+#endif
+
+#if defined(__NetBSD__)
+__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$NetBSD: symmetric.c,v 1.18 2010/11/07 08:39:59 agc Exp $");
+#endif
+
+#include "crypto.h"
+#include "packet-show.h"
+
+#include