Author: bapt
Date: Tue Sep 15 06:21:33 2015
New Revision: 287811
URL: https://svnweb.freebsd.org/changeset/base/287811

Log:
  MFC: r287579, r287810 (adapted to old openssl APIs)
  
  Implement pubkey support for the bootstrap
  
  Note that to not interfer with finger print it expects a signature on pkg 
itself
  which is named pkg.txz.pubkeysign
  
  To generate it:
  echo -n "$(sha256 -q pkg.txz)" | openssl dgst -sha256 -sign /thekey \
      -binary -out ./pkg.txz.pubkeysig
  
  Note the "echo -n" which prevent signing the '\n' one would get otherwise
  
  PR:           202622

Modified:
  stable/9/usr.sbin/pkg/config.c
  stable/9/usr.sbin/pkg/config.h
  stable/9/usr.sbin/pkg/pkg.c
Directory Properties:
  stable/9/usr.sbin/pkg/   (props changed)

Modified: stable/9/usr.sbin/pkg/config.c
==============================================================================
--- stable/9/usr.sbin/pkg/config.c      Tue Sep 15 05:56:16 2015        
(r287810)
+++ stable/9/usr.sbin/pkg/config.c      Tue Sep 15 06:21:33 2015        
(r287811)
@@ -131,6 +131,15 @@ static struct config_entry c[] = {
                false,
                true,
        },
+       [PUBKEY] = {
+               PKG_CONFIG_STRING,
+               "PUBKEY",
+               NULL,
+               NULL,
+               NULL,
+               false,
+               false
+       }
 };
 
 static const char *
@@ -347,6 +356,8 @@ config_parse(const ucl_object_t *obj, pk
                                sbuf_cpy(buf, "SIGNATURE_TYPE");
                        else if (strcasecmp(key, "fingerprints") == 0)
                                sbuf_cpy(buf, "FINGERPRINTS");
+                       else if (strcasecmp(key, "pubkey") == 0)
+                               sbuf_cpy(buf, "PUBKEY");
                        else if (strcasecmp(key, "enabled") == 0) {
                                if ((cur->type != UCL_BOOLEAN) ||
                                    !ucl_object_toboolean(cur))

Modified: stable/9/usr.sbin/pkg/config.h
==============================================================================
--- stable/9/usr.sbin/pkg/config.h      Tue Sep 15 05:56:16 2015        
(r287810)
+++ stable/9/usr.sbin/pkg/config.h      Tue Sep 15 06:21:33 2015        
(r287811)
@@ -40,6 +40,7 @@ typedef enum {
        SIGNATURE_TYPE,
        FINGERPRINTS,
        REPOS_DIR,
+       PUBKEY,
        CONFIG_SIZE
 } pkg_config_key;
 

Modified: stable/9/usr.sbin/pkg/pkg.c
==============================================================================
--- stable/9/usr.sbin/pkg/pkg.c Tue Sep 15 05:56:16 2015        (r287810)
+++ stable/9/usr.sbin/pkg/pkg.c Tue Sep 15 06:21:33 2015        (r287811)
@@ -66,6 +66,11 @@ struct sig_cert {
        bool trusted;
 };
 
+struct pubkey {
+       unsigned char *sig;
+       int siglen;
+};
+
 typedef enum {
        HASH_UNKNOWN,
        HASH_SHA256,
@@ -481,7 +486,30 @@ cleanup:
 }
 
 static RSA *
-load_rsa_public_key_buf(unsigned char *cert, int certlen)
+load_rsa_public_key_file(const char *file)
+{
+       RSA *rsa = NULL;
+       BIO *bp;
+       char errbuf[1024];
+
+       bp = BIO_new_file(file, "r");
+       if (!bp)
+               errx(EXIT_FAILURE, "Unable to read %s", file);
+
+       if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) {
+               warn("error reading public key: %s",
+                   ERR_error_string(ERR_get_error(), errbuf));
+               BIO_free(bp);
+               return (NULL);
+       }
+
+       BIO_free(bp);
+
+       return (rsa);
+}
+
+static RSA *
+load_rsa_public_key_buf(const unsigned char *cert, int certlen)
 {
        RSA *rsa = NULL;
        BIO *bp;
@@ -500,8 +528,8 @@ load_rsa_public_key_buf(unsigned char *c
 
 
 static bool
-rsa_verify_cert(int fd, unsigned char *key, int keylen,
-    unsigned char *sig, int siglen)
+rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key,
+    int keylen, unsigned char *sig, int siglen)
 {
        char sha256[SHA256_DIGEST_LENGTH *2 +1];
        char hash[SHA256_DIGEST_LENGTH];
@@ -518,7 +546,11 @@ rsa_verify_cert(int fd, unsigned char *k
 
        sha256_buf_bin(sha256, strlen(sha256), hash);
 
-       rsa = load_rsa_public_key_buf(key, keylen);
+       if (sigfile != NULL) {
+               rsa = load_rsa_public_key_file(sigfile);
+       } else {
+               rsa = load_rsa_public_key_buf(key, keylen);
+       }
        if (rsa == NULL)
                return (false);
        ret = RSA_verify(NID_sha256, hash, sizeof(hash), sig, siglen, rsa);
@@ -533,6 +565,35 @@ rsa_verify_cert(int fd, unsigned char *k
        return (true);
 }
 
+static struct pubkey *
+read_pubkey(int fd)
+{
+       struct pubkey *pk;
+       struct sbuf *sig;
+       char buf[4096];
+       int r;
+
+       if (lseek(fd, 0, 0) == -1) {
+               warn("lseek");
+               return (NULL);
+       }
+
+       sig = sbuf_new_auto();
+
+       while ((r = read(fd, buf, sizeof(buf))) >0) {
+               sbuf_bcat(sig, buf, r);
+       }
+
+       sbuf_finish(sig);
+       pk = calloc(1, sizeof(struct pubkey));
+       pk->siglen = sbuf_len(sig);
+       pk->sig = calloc(1, pk->siglen);
+       memcpy(pk->sig, sbuf_data(sig), pk->siglen);
+       sbuf_delete(sig);
+
+       return (pk);
+}
+
 static struct sig_cert *
 parse_cert(int fd) {
        int my_fd;
@@ -606,6 +667,45 @@ parse_cert(int fd) {
 }
 
 static bool
+verify_pubsignature(int fd_pkg, int fd_sig)
+{
+       struct pubkey *pk;
+       const char *pubkey;
+       bool ret;
+
+       pk = NULL;
+       pubkey = NULL;
+       ret = false;
+       if (config_string(PUBKEY, &pubkey) != 0) {
+               warnx("No CONFIG_PUBKEY defined");
+               goto cleanup;
+       }
+
+       if ((pk = read_pubkey(fd_sig)) == NULL) {
+               warnx("Error reading signature");
+               goto cleanup;
+       }
+
+       /* Verify the signature. */
+       printf("Verifying signature with public key %s... ", pubkey);
+       if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig,
+           pk->siglen) == false) {
+               fprintf(stderr, "Signature is not valid\n");
+               goto cleanup;
+       }
+
+       ret = true;
+
+cleanup:
+       if (pk) {
+               free(pk->sig);
+               free(pk);
+       }
+
+       return (ret);
+}
+
+static bool
 verify_signature(int fd_pkg, int fd_sig)
 {
        struct fingerprint_list *trusted, *revoked;
@@ -683,7 +783,7 @@ verify_signature(int fd_pkg, int fd_sig)
 
        /* Verify the signature. */
        printf("Verifying signature with trusted certificate %s... ", sc->name);
-       if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig,
+       if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig,
            sc->siglen) == false) {
                printf("failed\n");
                fprintf(stderr, "Signature is not valid\n");
@@ -751,24 +851,42 @@ bootstrap_pkg(bool force)
 
        if (signature_type != NULL &&
            strcasecmp(signature_type, "NONE") != 0) {
-               if (strcasecmp(signature_type, "FINGERPRINTS") != 0) {
-                       warnx("Signature type %s is not supported for "
-                           "bootstrapping.", signature_type);
-                       goto cleanup;
-               }
+               if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
+
+                       snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX",
+                           getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
+                       snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
+                           packagesite);
+
+                       if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
+                               fprintf(stderr, "Signature for pkg not "
+                                   "available.\n");
+                               goto fetchfail;
+                       }
 
-               snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX",
-                   getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
-               snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
-                   packagesite);
+                       if (verify_signature(fd_pkg, fd_sig) == false)
+                               goto cleanup;
+               } else if (strcasecmp(signature_type, "PUBKEY") == 0) {
 
-               if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
-                       fprintf(stderr, "Signature for pkg not available.\n");
-                       goto fetchfail;
-               }
+                       snprintf(tmpsig, MAXPATHLEN,
+                           "%s/pkg.txz.pubkeysig.XXXXXX",
+                           getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
+                       snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig",
+                           packagesite);
+
+                       if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
+                               fprintf(stderr, "Signature for pkg not "
+                                   "available.\n");
+                               goto fetchfail;
+                       }
 
-               if (verify_signature(fd_pkg, fd_sig) == false)
+                       if (verify_pubsignature(fd_pkg, fd_sig) == false)
+                               goto cleanup;
+               } else {
+                       warnx("Signature type %s is not supported for "
+                           "bootstrapping.", signature_type);
                        goto cleanup;
+               }
        }
 
        if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
@@ -842,21 +960,37 @@ bootstrap_pkg_local(const char *pkgpath,
        }
        if (signature_type != NULL &&
            strcasecmp(signature_type, "NONE") != 0) {
-               if (strcasecmp(signature_type, "FINGERPRINTS") != 0) {
-                       warnx("Signature type %s is not supported for "
-                           "bootstrapping.", signature_type);
-                       goto cleanup;
-               }
+               if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
 
-               snprintf(path, sizeof(path), "%s.sig", pkgpath);
+                       snprintf(path, sizeof(path), "%s.sig", pkgpath);
 
-               if ((fd_sig = open(path, O_RDONLY)) == -1) {
-                       fprintf(stderr, "Signature for pkg not available.\n");
-                       goto cleanup;
-               }
+                       if ((fd_sig = open(path, O_RDONLY)) == -1) {
+                               fprintf(stderr, "Signature for pkg not "
+                                   "available.\n");
+                               goto cleanup;
+                       }
 
-               if (verify_signature(fd_pkg, fd_sig) == false)
+                       if (verify_signature(fd_pkg, fd_sig) == false)
+                               goto cleanup;
+
+               } else if (strcasecmp(signature_type, "PUBKEY") == 0) {
+
+                       snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath);
+
+                       if ((fd_sig = open(path, O_RDONLY)) == -1) {
+                               fprintf(stderr, "Signature for pkg not "
+                                   "available.\n");
+                               goto cleanup;
+                       }
+
+                       if (verify_pubsignature(fd_pkg, fd_sig) == false)
+                               goto cleanup;
+
+               } else {
+                       warnx("Signature type %s is not supported for "
+                           "bootstrapping.", signature_type);
                        goto cleanup;
+               }
        }
 
        if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to