Module Name:    src
Committed By:   agc
Date:           Fri Sep 10 05:15:16 UTC 2010

Added Files:
        src/crypto/external/bsd/netpgp/dist/src/libpaa:
            PubKeyAccessAuthScheme.txt client.c libpaa.3 libpaa.c libpaa.h
            server.c

Log Message:
Add an implementation of the Pubkey Access Authentication Scheme proposed
by Oliver Gould in

        http://www.olix0r.net/PubKeyAccessAuthScheme.txt

This implementation includes an example client and server program, but
is not (yet) hooked into the build.

To quote from Oliver's RFC:

        HTTP services are a core Internet technology, yet the Digest
        authentication scheme provided by RFC 2617 only describes
        authentication by way of shared-secrets (i.e.  passwords).
        This model has operational drawbacks, as authenticating
        services are required to have access to a user's secret (or a
        hash thereof), or retrograde technologies, such as cookies,
        are employed.

        Similarly to SSH's "publickey" authentication method [RFC
        4252], the PubKey Access Authentication scheme allows an HTTP
        server to authenticate clients using public key credentials.

        Like the Digest Access Authentication Scheme [RFC 2617], the
        PubKey.v1 scheme is based on a simple challenge-response
        paradigm.  The PubKey scheme responds to unauthorized clients
        with a challenge value; and a valid response contains a
        cryptographic signature of client's id, the authentication
        realm, and the server's challenge.

        The client's secret never leaves the client.  The server
        verifies the client's signed authorization request with the
        client's published public keys.

libpaa(3) uses libnetpgp(3) for its digital signatures, SHA1Init(3)
for digests, and base64 encoding for transmission of data.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 \
    src/crypto/external/bsd/netpgp/dist/src/libpaa/PubKeyAccessAuthScheme.txt \
    src/crypto/external/bsd/netpgp/dist/src/libpaa/client.c \
    src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.3 \
    src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.c \
    src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.h \
    src/crypto/external/bsd/netpgp/dist/src/libpaa/server.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/crypto/external/bsd/netpgp/dist/src/libpaa/PubKeyAccessAuthScheme.txt
diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libpaa/PubKeyAccessAuthScheme.txt:1.1
--- /dev/null	Fri Sep 10 05:15:16 2010
+++ src/crypto/external/bsd/netpgp/dist/src/libpaa/PubKeyAccessAuthScheme.txt	Fri Sep 10 05:15:16 2010
@@ -0,0 +1,417 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+DRAFT VERSION 0.4.2
+
+
+Oliver Vaughn Gould <v...@olix0r.net>
+July 2010
+
+
+  PubKey Access Authentication Scheme, Version 1
+  ----------------------------------------------
+
+  0  Introduction
+  --------------
+
+  0.1  Status of this Memo
+  ------------------------
+
+This document specifies a DRAFT protocol for the Internet community.
+
+
+  0.2  Copyright Notice
+  ---------------------
+
+Copyright (C) Yahoo!, Inc. (2010).  All rights reseved.
+
+
+  0.3  Abstract
+  -------------
+
+HTTP services are a core Internet technology, yet the Digest authentication
+scheme provided by RFC 2617 only describes authentication by way of
+shared-secrets (i.e. passwords).
+
+The PubKey Access Authentication scheme aims to enhance security on the
+World Wide Web by bringing an equivalent of SSH's "publickey" authentication
+method to challenge-based HTTP client authentication.
+
+
+  0.4  Table of Contents
+  ----------------------
+
+  1  PubKey Access Authentication Scheme, Version 1
+  1.1  Introduction
+  1.1.1  Purpose
+  1.1.2  Overall Operation
+  1.2  Specification of PubKey.v1 Headers
+  1.2.1  The WWW-Authenticate Response Header
+  1.2.2  The Authorize Request Header
+  1.3  Example
+  1.4  Proxy-Authentication and Proxy-Authorization
+  1.5  Operational Considerations
+  1.5.1  Replay Attacks
+  1.5.2  Man-in-the-Middle Attacks
+  1.5.3  Brute Force Attacks
+  1.5.4  Spoofing by Counterfeit Servers
+  2  References
+  A  Appendices
+  A.1  Challenge Generation
+
+
+  1  PubKey Access Authentication Scheme, Version 1
+  -------------------------------------------------
+
+  1.1  Introduction
+  -----------------
+
+  1.1.1  Purpose
+  --------------
+
+HTTP services are a core Internet technology, yet the Digest authentication
+scheme provided by RFC 2617 only describes authentication by way of
+shared-secrets (i.e. passwords).  This model has operational drawbacks, as
+authenticating services are required to have access to a user's secret (or
+a hash thereof), or retrograde technologies, such as cookies, are employed.
+
+Similarly to SSH's "publickey" authentication method [RFC 4252], the PubKey
+Access Authentication scheme allows an HTTP server to authenticate clients using
+public key credentials.
+
+
+  1.1.2  Overall Operation
+  ------------------------
+
+Like the Digest Access Authentication Scheme [RFC 2617], the PubKey.v1
+scheme is based on a simple challenge-response paradigm.  The PubKey scheme
+responds to unauthorized clients with a challenge value; and a valid
+response contains a cryptographic signature of client's id, the authentication
+realm, and the server's challenge.
+
+The client's secret never leaves the client.  The server verifies the
+client's signed authorization request with the client's published public
+keys.  
+
+
+  1.2  Specification of PubKey.v1 Headers
+  ---------------------------------------
+
+  1.2.1  The WWW-Authenticate Response Header
+  -------------------------------------------
+
+If a server receives a request for an access-protected object, and an
+acceptable Authorization header is not sent, the server responds with a
+"401 Unauthorized" status code, and a WWW-Authenticate header as per the
+framework defined above, which for the digest scheme is utilized as
+follows:
+
+    challenge         = "PubKey.v1" pubkey-challenge
+
+    pubkey-challenge  = 1#( realm | [domain] | challenge )
+
+    realm             = "realm" "=" quoted-string
+    domain            = "domain" "=" <"> URI ( 1*SP URI ) <">
+    URI               = absoluteURI | abs_path
+    challenge         = "challenge" "=" quoted-string
+
+The meanings of the values of the directives used above are as follows:
+
+    realm
+      A string to be displayed to clients so they know which username and
+      public key to use.  This string should contain at least the name of
+      the host performing the authentication and might additionally
+      indicate the collection of users who might have access.  An example
+      might be "ad...@svc.domain.tld".
+
+    domain
+      An optional quoted, space-separated list of URIs that define the
+      protection space.  If a URI is an abs_path, it is relative to the
+      canonical root URL of the server being accessed.  An absoluteURI in this
+      list may refer to a different server than the one being accessed.  The
+      client can use this list to determine the set of URIs for which the same
+      authentication information may be sent: any URI that has a URI in this
+      list as a prefix (after both have been made absolute) may be assumed to be
+      in the same protection space.  If this directive is omitted or its value
+      is empty, the client should assume that the protection space consists of
+      all URIs on the responding server.
+
+      This directive is not meaningful in Proxy-Authenticate headers, for
+      which the protection space is always the entire proxy; if present it
+      should be ignored.
+
+    challenge
+      A quoted string of data, specified by the server, which should be returned
+      by the client unchanged in the Authorization header of subsequent
+      requests with URIs in the same protection space.  It is recommended
+      that this string be base 64 or hexadecimal data.
+
+
+  1.2.2  The Authorization Request Header
+  -------------------------------------
+
+The client is expected to retry the request, passing an Authorization
+header line, which is defined according to the framework above, utilized as
+follows.
+
+    credentials          = "PubKey.v1" privkey-credentials
+
+    privkey-credentials  = 1#( identifier | realm | challenge | signature )
+
+    identifier           = "id" "=" identifier-value
+    identifier-value     = quoted-string
+    challenge            = "challenge" "=" challenge-value
+    challenge-value      = quoted-string
+    signature            = "signature" "=" signature-value
+    signature-value      = quoted-string
+
+The values of the challenge and realm fields must be those supplied in the
+WWW-Authenticate response header for the entity being requested.
+
+    identifier
+      The client identifier in the specified realm.  I.e. the client's username.
+
+    signature
+      A quoted base 64 encoded string representation of a signature generated
+      with the client's private key as follows.
+
+          signature = BASE64( D^M( authorization ))
+          authorization = identifier-value ";" realm-value ";" challenge-value
+
+If a directive or its value is improper, or required directives are
+missing, the proper response is 400 Bad Request.  If the signature is
+invalid, then a login failure should be logged, since repeated login
+failures from a single client may indicate malfeasance.
+
+The client should be able to reuse this Authorization until a 401
+Unauthorized is reached, or an Authentication-Info header provides a new
+challenge.
+
+
+  1.2.3  Authentication-Info Header
+  ---------------------------------
+
+The optional Authentication-Info header may be used by the server to
+communicate some information regarding the successful authentication in the
+response.  Specifically, this header can be used to send a new challenge to
+an authorized client.
+
+    AuthenticationInfo = "Authentication-Info" ":" auth-info
+    auth-info          =  1#( next-challenge  )
+    next-challenge     =  "challenge" "=" challenge-value
+
+The meanings of the values used above are as follows:
+
+    next-challenge
+      The following request on this domain should contain an authorization
+      on this challenge value.  It should be expected that reissuing the
+      used Authorization header will result in a 401 Unauthorized response.
+
+
+  1.3  Example
+  ------------
+
+The following example assumes that an access-protected resource is being
+requested from the server via a GET request.  The URI of the document is
+"http://svc.domain.tld/object";.  Both client and server know the public key
+for the user identified as "McFly" in the realm "us...@svc.domain.tld".
+
+The first time the client requests the document, no Authorization header is
+sent, so the server responds with:
+
+    401 Unauthorized
+    WWW-Authenticate: PubKey.v1
+        challenge="aKMpP2pkd3qiDnOUAHJ+pB1VdphaR2tFSF4J7wLWODk=;dXNlcnNAc3ZjLmRvbWFpbi50bGQ7MTI3ODExMjc5OTsxMjcuMC4wLjE7bThvK3JUa29rRVFPMFFLRUh2L280dz09",
+        realm="us...@svc.domain.tld"
+
+The client's user agent determines the client's identifier and private key
+to use for the realm.  The user agent then uses this private key to sign
+the server's challenge, prompting the user as neccessary.  Finally, the
+client sends a new request including the Authorization header:
+
+    Authorization: PubKey.v1
+        id="McFly",
+        challenge="aKMpP2pkd3qiDnOUAHJ+pB1VdphaR2tFSF4J7wLWODk=;dXNlcnNAc3ZjLmRvbWFpbi50bGQ7MTI3ODExMjc5OTsxMjcuMC4wLjE7bThvK3JUa29rRVFPMFFLRUh2L280dz09",
+        realm="us...@svc.domain.tld",
+        signature="AAAAB3NzaC1yc2EAAAEAWARe6cScN5t0aFy0lBA1EbC/JoyRxsEuPsWtFZ3qw12lXYcmTXuq1v/0lwqcgZQgutQdiavR6O6157uyk0dkfuDXiuOjsngkmgp0oN/kwYxKPVrXMze1tFr8tFBUQU+JeCbvVd+o6LeD7pO29onXqf776N21nX1sRaeT+wX6qNMNEgJ7S3TzwTgMJ4Ub5dMCxXYCX7AW15YzLie213fvU3YiBh1ZHy//ubDb29d/2t941/gAdipjRQiabWK5lpfkmLJWJddlZq3IyFqiXMM1vpaGmiiM5w2fMpuzO8enyRTDtQQwLAxrffxY/n6RbGvUiEU4YzSGLlPE6KUU36dKOw=="
+
+The server verifies the client's signature on the following authorization
+string:
+
+   McFly;us...@svc.domain.tld;aKMpP2pkd3qiDnOUAHJ+pB1VdphaR2tFSF4J7wLWODk=;dXNlcnNAc3ZjLmRvbWFpbi50bGQ7MTI3ODExMjc5OTsxMjcuMC4wLjE7bThvK3JUa29rRVFPMFFLRUh2L280dz09
+
+Assuming that the challenge generation algorithm described in section A.1
+is used, the server then verfies its own signature of the challenge by
+decoding the challenge thusly:
+
+    b64-server-signature = "aKMpP2pkd3qiDnOUAHJ+pB1VdphaR2tFSF4J7wLWODk="
+    b64-challenge = "dXNlcnNAc3ZjLmRvbWFpbi50bGQ7MTI3ODExMjc5OTsxMjcuMC4wLjE7bThvK3JUa29rRVFPMFFLRUh2L280dz09"
+    challenge = "us...@svc.domain.tld;1278112799;127.0.0.1;m8o+rTkokEQO0QKEHv/o4w=="
+
+After the server's signature is verified, it checks the realm, expiration, and
+source IP encoded in the challenge to authorize the request.  
+
+
+  1.4  Proxy-Authentication and Proxy-Authorization
+  -------------------------------------------------
+
+The PubKey.v1 authentication scheme may also be used for authenticating
+clients to proxies, proxies to proxies, or proxies to origin servers by use
+of the Proxy-Authenticate and Proxy-Authorization headers.  These headers
+are instances of the Proxy-Authenticate and Proxy-Authorization headers
+specified in sections 10.33 and 10.34 of the HTTP/1.1 specification [RFC
+2616] and their behavior is subject to restrictions described there.  The
+transactions for proxy authentication are very similar to those already
+described.  Upon receiving a request which requires authentication, the
+proxy/server must issue the "407 Proxy Authentication Required" response
+with a "Proxy-Authenticate" header.  The pubkey-challenge used in the
+Proxy-Authenticate header is the same as that for the WWW-Authenticate
+header as defined above in section 1.2.1.
+
+The client/proxy must then re-issue the request with a Proxy-Authorization
+header, with directives as specified for the Authorization header in
+section 1.2.2 above.
+
+Note that in principle a client could be asked to authenticate itself to
+both a proxy and an end-server, but never in the same response.
+
+
+  1.5  Operational Considerations
+  -------------------------------
+
+  1.5.1  Replay Attacks
+  ---------------------
+
+The challenge generation scheme described in section A.1 includes a
+server-signed time, client IP address, and random seed; after verifying its own
+signature, the server verifies that the authorized request is from the expected
+source and within the allowed session time.
+
+The server may preempt the need for an expired transaction by sending a new
+challenge in an AuthorizationInfo header.
+
+
+  1.5.2  Man-in-the-Middle Attacks
+  --------------------------------
+
+In principal, it is not possible to distinguish untrusted intermediaries
+from trustworthy (e.g. HTTP or SOCKS) proxy servers.  Therefore, the
+PubKey.v1 scheme does not attempt to implement any form of server
+authentication or endpoint confidentiality.  A client's Authorization token
+may be stolen by intermediary servers.  
+
+Some form of socket-or-application-layer cryptography should be utilized to
+establish confidentiality between endpoints.
+
+
+  1.5.3  Brute Force Attacks
+  --------------------------
+
+Brute force attacks against strong cryptographic keys (currently, RSA 2048
+or stronger) are particularly ineffective, which is a major advantage of this
+authentication scheme over, for instance, the Digest scheme.
+
+The challenge generation algorithm described in section A.1 uses a secret
+value and digest algorithm to verify the returned, signed challenge.  If an
+authorized attacker gains access to this value and determine the digest
+algorithm, it can override values encoded in the server's challenge.  Note
+that such an attack can only be exploited by sending a manipulated challenge
+value with a valid signature from a client authorized to the given realm.
+
+The randomized seed value in the challenge helps to mitigate cryptanalytic
+attacks on the server's secret by introducing entropy into the signature.
+
+
+  1.5.4  Spoofing by Counterfeit Servers
+  --------------------------------------
+
+The PubKey.v1 authentication scheme does not provide any means for a client
+to validate a server.
+
+Some form of socket-or-application-layer cryptography should be utilized to
+establish confidentiality between endpoints.
+
+
+  2 References
+  ------------
+
+[RFC 2222]  Simple Authentication and Security Layer (SASL)
+[RFC 2616]  Hypertext Transfer Protocol -- HTTP/1.1
+[RFC 2617]  HTTP Authentication: Basic and Digest Access Authentication
+[RFC 2818]  HTTP Over TLS
+[RFC 2743]  Generic Security Service Application Program Interface
+            Version 2, Update 1
+[RFC 4251]  The Secure Shell (SSH) Protocol Architecture
+[RFC 4252]  The Secure Shell (SSH) Authentication Protocol
+
+
+Portions of this document were based directly on these references:
+  Copyright (C) The Internet Society (1999, 2006).  All Rights Reserved.
+
+
+  A  Appendices
+  -------------
+
+  A.1  Challenge Generation
+  -------------------------
+
+- From a client's perspective, the challenge value is an opaque blob of data
+to be signed.  However, the server can encode data into its challenge value
+in order to authenticate clients without maintaining state for all such
+requests.  One possible challenge generation scheme is discussed below, but
+it can be replaced with no impact on the protocol.
+
+    challenge-value = server-signature ";" encoded-challenge
+
+    server-signature = BASE64( DIGEST( raw-server-signature ) )
+    raw-server-signature = raw-challenge ";" server-secret-value
+
+    encoded-challenge = BASE64( raw-challenge )
+
+    raw-challenge = realm-value ";" ip-address ";" epoch-time ";" seed-value 
+
+    epoch-time = integer
+    ip-address = <IPv4 or IPv6 address>
+    seed-value = token [RFC 2616]
+    server-secret-value = token [RFC 2616]
+
+The meanings of the values used above are as follows:
+
+    DIGEST
+      A digest algorithm such as SHA256.
+
+    epoch-time
+      The time at which the challenge was generated.  The server may reference
+      this field to determine whether the authorization has expired.
+
+    ip-address
+      The IP address of the client-side of the connection on which the request
+      is being made.
+
+    realm-value
+      The realm-value specified in the WWW-Authenticate.
+
+    seed-value
+      A random value generated by the server to introduce entropy into the
+      server's signatures.
+
+    server-secret-value
+      A secret value that only the server may access.  This is used to
+      'sign' a challenge.  The client's Authorization is validated by
+      reconstructing the challenge with this secret.
+
+      It would also be possible for a server to use a private key instead
+      of a server-secret-value.
+
+Depending on the server's resources, it may be desirable to use a cipher
+algorithm instead of a digest algorithm.
+
+
+DRAFT VERSION 0.4.2
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2.0.14 (GNU/Linux)
+
+iEYEARECAAYFAkxJEZ0ACgkQkPEZLwKUCCVZeQCfb7zuztnPcEjCBF5CPtwaLJTd
+xrgAoJ4etR3erN/PstMEOJc1mjRR7OXr
+=R8Im
+-----END PGP SIGNATURE-----
Index: src/crypto/external/bsd/netpgp/dist/src/libpaa/client.c
diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libpaa/client.c:1.1
--- /dev/null	Fri Sep 10 05:15:16 2010
+++ src/crypto/external/bsd/netpgp/dist/src/libpaa/client.c	Fri Sep 10 05:15:16 2010
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2010 Alistair Crooks <a...@netbsd.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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 <sys/types.h>
+
+#include <netdb.h>
+
+#include <netpgp.h>
+#include <regex.h>
+#include <sha1.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "libpaa.h"
+
+#define DEFAULT_HASH_ALG "SHA256"
+
+int
+main(int argc, char **argv)
+{
+	paa_response_t	response;
+	netpgp_t	netpgp;
+	char		challenge[2048];
+	char		buf[2048];
+	int		challengec;
+	int		cc;
+	int		i;
+
+	(void) memset(&response, 0x0, sizeof(response));
+	(void) memset(&netpgp, 0x0, sizeof(netpgp));
+	while ((i = getopt(argc, argv, "S:d:r:u:")) != -1) {
+		switch(i) {
+		case 'S':
+			netpgp_setvar(&netpgp, "ssh keys", "1");
+			netpgp_setvar(&netpgp, "sshkeyfile", optarg);
+			break;
+		case 'd':
+			//challenge.domain = optarg;
+			break;
+		case 'r':
+			//challenge.realm = optarg;
+			response.realm = optarg;
+			break;
+		case 'u':
+			netpgp_setvar(&netpgp, "userid", optarg);
+			break;
+		}
+	}
+	netpgp_setvar(&netpgp, "hash", DEFAULT_HASH_ALG);
+	netpgp_setvar(&netpgp, "need seckey", "1");
+	netpgp_setvar(&netpgp, "need userid", "1");
+	netpgp_set_homedir(&netpgp, getenv("HOME"),
+			netpgp_getvar(&netpgp, "ssh keys") ? "/.ssh" : "/.gnupg", 1);
+	if (!netpgp_init(&netpgp)) {
+		(void) fprintf(stderr, "can't initialise netpgp\n");
+		exit(EXIT_FAILURE);
+	}
+	/* read challenge into challenge */
+	challengec = read(0, challenge, sizeof(challenge));
+	cc = paa_format_response(&response, &netpgp, challenge, buf, sizeof(buf));
+	write(1, buf, cc);
+	exit(EXIT_SUCCESS);
+}
Index: src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.3
diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.3:1.1
--- /dev/null	Fri Sep 10 05:15:16 2010
+++ src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.3	Fri Sep 10 05:15:16 2010
@@ -0,0 +1,117 @@
+.\" $NetBSD: libpaa.3,v 1.1 2010/09/10 05:15:16 agc Exp $
+.\"
+.\" Copyright (c) 2009,2010 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This manual page is derived from software contributed to The
+.\" NetBSD Foundation by Alistair Crooks (a...@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.
+.\"
+.Dd September 9, 2010
+.Dt LIBPAA 3
+.Os
+.Sh NAME
+.Nm libpaa
+.Nd Public key Access Authentication Library
+.Sh LIBRARY
+.Lb libpaa
+.Sh SYNOPSIS
+.In libpaa.h
+.Ft int
+.Fo paa_server_init
+.Fa "paa_server_info_t *server" "unsigned secretsize"
+.Fc
+.Ft int
+.Fo paa_format_challenge
+.Fa "paa_challenge_t *challenge" "paa_server_info_t *server"
+.Fa "char *buf" "size_t size"
+.Fc
+.Ft int
+.Fo paa_format_response
+.Fa "paa_response_t *response" "netpgp_t *netpgp" "char *in"
+.Fa "char *out" "size_t outsize"
+.Fc
+.Ft int
+.Fo paa_check_response
+.Fa "paa_challenge_t *challenge" "paa_identity_t *id"
+.Fa "netpgp_t *netpgp" "char *response"
+.Fc
+.Ft int
+.Fo paa_print_identity
+.Fa "FILE *fp" "paa_identity_t *id"
+.Fc
+.Sh DESCRIPTION
+.Nm
+is a library interface which provides an authentication mechanism
+layered on top of
+.Xr libnetpgp 3 .
+This is targeted at web services, and allows authentication by
+means of digitally signing a generated challenge.
+By verifying the signed response from the client, the server
+can verify the identity of the user receiving the challenge,
+and producing the signed response.
+Random seeds and blinded secrets are used to protect against
+spoofed signatures.
+.Pp
+The main reason for writing this authentication mechanism is
+so that identities can be verified across a network without
+transferring any secret information across the wire.
+.Pp
+Binary information is transferred using internal base64
+functions.
+.Pp
+In the server
+process, the server information is initialised using the
+.Fn paa_server_init
+function, which will set up the random data and secrets.
+The challenge is generated using the
+.Fn paa_format_challenge
+function.
+This will format the challenge into the buffer provided,
+and can be transferred to the client using any means.
+.Pp
+The client reads the challenge, and produces a response
+using the
+.Fn paa_format_response
+function to format the response in the buffer provided.
+This response is given to the server.
+.Pp
+In the server, the response is verified using
+the
+.Fn paa_check_response
+function.
+If a postive verification has occurred, the identity of
+various fields in the response can be displayed
+using the
+.Fn paa_print_identity
+function.
+.Sh SEE ALSO
+.Xr libnetpgp 3 ,
+.Xr sha1 3
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Nx 6.0 .
+.Sh AUTHORS
+.An Alistair Crooks Aq a...@netbsd.org
Index: src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.c
diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.c:1.1
--- /dev/null	Fri Sep 10 05:15:16 2010
+++ src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.c	Fri Sep 10 05:15:16 2010
@@ -0,0 +1,387 @@
+/*-
+ * Copyright (c) 2010 Alistair Crooks <a...@netbsd.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <netinet6/in6.h>
+
+#include <netdb.h>
+
+#include <ifaddrs.h>
+#include <netpgp.h>
+#include <regex.h>
+#include <sha1.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "libpaa.h"
+#include "b64.h"
+
+enum {
+	MAX_DIGEST_SIZE	= 128
+};
+
+/* create an area of random memory */
+static int
+randomise(char *s, size_t size)
+{
+	uint32_t	r;
+	size_t		i;
+
+	for (i = 0 ; i < size ; i += sizeof(r)) {
+		r = random();
+		(void) memcpy(&s[i], &r, sizeof(r));
+	}
+	return i;
+}
+
+/* generate a challenge */
+static int
+genchallenge(paa_challenge_t *challenge, paa_server_info_t *server)
+{
+	time_t		 t;
+	char		 digest[MAX_DIGEST_SIZE];
+	char		 raw[PAA_CHALLENGE_SIZE * 2];
+	int		 cc;
+
+	t = time(NULL);
+	cc = snprintf(raw, sizeof(raw), "%s;%s;%lld;", challenge->realm, server->hostaddress, (int64_t)t);
+	cc += randomise(&raw[cc], 64);	/* 64 is arbitrary */
+	/* raw now has the raw-challenge in it */
+	challenge->encc = b64encode(raw, (const unsigned)cc, challenge->encoded_challenge,
+		sizeof(challenge->encoded_challenge), 0);
+	cc += snprintf(&raw[cc], sizeof(raw) - cc, ";%.*s", server->secretc, server->secret);
+	(void) SHA1Data((uint8_t *)raw, (unsigned)cc, digest);
+	server->server_signaturec = b64encode(digest, (const unsigned)strlen(digest),
+		server->server_signature, sizeof(server->server_signature), (int)0);
+	/* raw has raw-challenge ; server-secret-value, i.e. raw-server-signature */
+	challenge->challengec = snprintf(challenge->challenge, sizeof(challenge->challenge),
+		"%.*s;%.*s", server->server_signaturec, server->server_signature,
+		challenge->encc, challenge->encoded_challenge);
+	return challenge->challengec;
+}
+
+/* fill in the identity information in the response */
+static int
+fill_identity(paa_identity_t *id, char *response, char *raw_challenge)
+{
+	regmatch_t	matches[10];
+	regex_t		response_re;
+	regex_t		id_re;
+	char		t[32];
+
+	/* id="userid" */
+	(void) regcomp(&id_re, "id=\"([^\"]+)\"", REG_EXTENDED);
+	if (regexec(&id_re, response, 10, matches, 0) != 0) {
+		(void) fprintf(stderr, "No identity information found\n");
+		return 0;
+	}
+	(void) snprintf(id->userid, sizeof(id->userid), "%.*s",
+		(int)(matches[1].rm_eo - matches[1].rm_so),
+		&response[(int)matches[1].rm_so]);
+	/* realm;ip;timestamp;seed */
+	(void) regcomp(&response_re, "([^;]+);([^;]+);([^;]+);(.*)", REG_EXTENDED);
+	if (regexec(&response_re, raw_challenge, 10, matches, 0) != 0) {
+		(void) fprintf(stderr, "No identity information found\n");
+		return 0;
+	}
+	(void) snprintf(id->realm, sizeof(id->realm), "%.*s",
+		(int)(matches[1].rm_eo - matches[1].rm_so),
+		&raw_challenge[(int)matches[1].rm_so]);
+	(void) snprintf(id->client, sizeof(id->client), "%.*s",
+		(int)(matches[2].rm_eo - matches[2].rm_so),
+		&raw_challenge[(int)matches[2].rm_so]);
+	(void) snprintf(t, sizeof(t), "%.*s",
+		(int)(matches[3].rm_eo - matches[3].rm_so),
+		&raw_challenge[(int)matches[3].rm_so]);
+	id->timestamp = strtoll(t, NULL, 10);
+	return 1;
+}
+
+/***************************************************************************/
+/* exported functions start here */
+/***************************************************************************/
+
+/* initialise the server info */
+int
+paa_server_init(paa_server_info_t *server, unsigned secretsize)
+{
+	struct sockaddr_in6	*sin6;
+	struct sockaddr_in	*sin;
+	struct ifaddrs		*addrs;
+	char			 host[512];
+
+	if (getifaddrs(&addrs) < 0) {
+		(void) fprintf(stderr, "can't getifaddrs\n");
+		return 0;
+	}
+	for ( ; addrs ; addrs = addrs->ifa_next) {
+		if (addrs->ifa_addr->sa_family == AF_INET) {
+			sin = (struct sockaddr_in *)(void *)addrs->ifa_addr;
+			(void) snprintf(server->hostaddress, sizeof(server->hostaddress), "%s",
+				inet_ntoa(sin->sin_addr));
+			break;
+		}
+		if (addrs->ifa_addr->sa_family == AF_INET6) {
+			sin6 = (struct sockaddr_in6 *)(void *)addrs->ifa_addr;
+			(void) getnameinfo((const struct sockaddr *)(void *)sin6,
+				(unsigned)sin6->sin6_len,
+				server->hostaddress, sizeof(server->hostaddress),
+				NULL, 0, NI_NUMERICHOST);
+			break;
+		}
+	}
+	if (addrs == NULL) {
+		if (gethostname(host, sizeof(host)) < 0) {
+			(void) fprintf(stderr, "can't get hostname\n");
+			return 0;
+		}
+		(void) snprintf(server->hostaddress, sizeof(server->hostaddress), "%s", host);
+	}
+	if ((server->secret = calloc(1, server->secretc = secretsize)) == NULL) {
+		(void) fprintf(stderr, "can't allocate server secret\n");
+		return 0;
+	}
+	server->secretc = randomise(server->secret, secretsize);
+	return 1;
+}
+
+/*
+    challenge         = "PubKey.v1" pubkey-challenge
+
+    pubkey-challenge  = 1#( realm | [domain] | challenge )
+
+    realm             = "realm" "=" quoted-string
+    domain            = "domain" "=" <"> URI ( 1*SP URI ) <">
+    URI               = absoluteURI | abs_path
+    challenge         = "challenge" "=" quoted-string
+*/
+
+/* called from server to send the challenge */
+int
+paa_format_challenge(paa_challenge_t *challenge, paa_server_info_t *server, char *buf, size_t size)
+{
+	int	cc;
+
+	if (challenge->realm == NULL) {
+		(void) fprintf(stderr, "paa_format_challenge: no realm information\n");
+		return 0;
+	}
+	cc = snprintf(buf, size, "401 Unauthorized\r\nWWW-Authenticate: PubKey.v1\r\n");
+	(void) genchallenge(challenge, server);
+	cc += snprintf(&buf[cc], size - cc, "    challenge=\"%s\"", challenge->challenge);
+	if (challenge->realm) {
+		cc += snprintf(&buf[cc], size - cc, ",\r\n    realm=\"%s\"", challenge->realm);
+	}
+	if (challenge->domain) {
+		cc += snprintf(&buf[cc], size - cc, ",\r\n    domain=\"%s\"", challenge->domain);
+	}
+	cc += snprintf(&buf[cc], size - cc, "\r\n");
+	return cc;
+}
+
+/*
+    credentials          = "PubKey.v1" privkey-credentials
+
+    privkey-credentials  = 1#( identifier | realm | challenge | signature )
+
+    identifier           = "id" "=" identifier-value
+    identifier-value     = quoted-string
+    challenge            = "challenge" "=" challenge-value
+    challenge-value      = quoted-string
+    signature            = "signature" "=" signature-value
+    signature-value      = quoted-string
+*/
+
+/* called from client to respond to the challenge */
+int
+paa_format_response(paa_response_t *response, netpgp_t *netpgp, char *in, char *out, size_t outsize)
+{
+	regmatch_t	matches[10];
+	regex_t		r;
+	char		challenge[2048 * 2];
+	char		base64_signature[2048 * 2];
+	char		sig[2048];
+	int		challengec;
+	int		sig64c;
+	int		sigc;
+	int		outc;
+
+	if (response->realm == NULL) {
+		(void) fprintf(stderr, "paa_format_response: no realm information\n");
+		return 0;
+	}
+	(void) regcomp(&r, "challenge=\"([^\"]+)\"", REG_EXTENDED);
+	if (regexec(&r, in, 10, matches, 0) != 0) {
+		(void) fprintf(stderr, "no signature found\n");
+		return 0;
+	}
+	challengec = snprintf(challenge, sizeof(challenge), "%.*s",
+		(int)(matches[1].rm_eo - matches[1].rm_so), &in[(int)matches[1].rm_so]);
+	/* read challenge string */
+	outc = snprintf(out, outsize, "Authorization: PubKey.v1\r\n");
+	response->userid = netpgp_getvar(netpgp, "userid");
+	outc += snprintf(&out[outc], outsize - outc, "    id=\"%s\"", response->userid);
+	outc += snprintf(&out[outc], outsize - outc, ",\r\n    challenge=\"%s\"", challenge);
+	outc += snprintf(&out[outc], outsize - outc, ",\r\n    realm=\"%s\"", response->realm);
+	/* set up response */
+	(void) memset(sig, 0x0, sizeof(sig));
+	(void) snprintf(sig, sizeof(sig), "%s;%s;%s;", response->userid, response->realm, challenge);
+	sigc = netpgp_sign_memory(netpgp, response->userid, challenge,
+		(unsigned)challengec, sig, sizeof(sig), 0, 0);
+	sig64c = b64encode(sig, (const unsigned)sigc, base64_signature,
+		sizeof(base64_signature), (int)0);
+	outc += snprintf(&out[outc], outsize - outc, ",\r\n    signature=\"%.*s\"", sig64c, base64_signature);
+	return outc;
+}
+
+/* called from server to check the response to the challenge */
+int
+paa_check_response(paa_challenge_t *challenge, paa_identity_t *id, netpgp_t *netpgp, char *response)
+{
+	regmatch_t	matches[10];
+	regex_t		challenge_regex;
+	regex_t		signature_regex;
+	regex_t		realm_regex;
+	time_t		t;
+	char		encoded_challenge[512];
+	char		raw_challenge[512];
+	char		verified[2048];
+	char		realm[128];
+	char		buf[2048];
+	int		bufc;
+
+	/* grab the signed text from the response */
+	(void) regcomp(&signature_regex, "signature=\"([^\"]+)\"", REG_EXTENDED);
+	if (regexec(&signature_regex, response, 10, matches, 0) != 0) {
+		(void) fprintf(stderr, "paa_check: no signature found\n");
+		return 0;
+	}
+	/* atob the signature itself */
+	bufc = b64decode(&response[(int)matches[1].rm_so],
+		(size_t)(matches[1].rm_eo - matches[1].rm_so), buf, sizeof(buf));
+	/* verify the signature */
+	(void) memset(verified, 0x0, sizeof(verified));
+	if (netpgp_verify_memory(netpgp, buf, (const unsigned)bufc, verified, sizeof(verified), 0) <= 0) {
+		(void) fprintf(stderr, "paa_check: signature cannot be verified\n");
+		return 0;
+	}
+	/* we check the complete signed text against our challenge */
+	if (strcmp(challenge->challenge, verified) != 0) {
+		(void) fprintf(stderr, "paa_check: signature does not match\n");
+		return 0;
+	}
+	(void) regcomp(&challenge_regex, "^([^;]+);(.+)", REG_EXTENDED);
+	if (regexec(&challenge_regex, verified, 10, matches, 0) != 0) {
+		(void) fprintf(stderr, "paa_check: no 2 parts to challenge\n");
+		return 0;
+	}
+	/* we know server signature matches from comparison on whole challenge above */
+	(void) snprintf(encoded_challenge, sizeof(encoded_challenge), "%.*s",
+		(int)(matches[2].rm_eo - matches[2].rm_so), &verified[(int)matches[2].rm_so]);
+	(void) b64decode(&verified[(int)matches[2].rm_so],
+		(const unsigned)(matches[2].rm_eo - matches[2].rm_so),
+		raw_challenge, sizeof(raw_challenge));
+	if (!fill_identity(id, response, raw_challenge)) {
+		(void) fprintf(stderr, "paa_check: identity problems\n");
+		return 0;
+
+	}
+	/* check realm info in authentication header matches signed realm */
+	(void) regcomp(&realm_regex, "realm=\"([^\"]+)\"", REG_EXTENDED);
+	if (regexec(&realm_regex, response, 10, matches, 0) != 0) {
+		(void) fprintf(stderr, "paa_check: no realm found\n");
+		return 0;
+	}
+	(void) snprintf(realm, sizeof(realm), "%.*s",
+		(int)(matches[1].rm_eo - matches[1].rm_so),
+		&response[(int)matches[1].rm_so]);
+	if (strcmp(id->realm, realm) != 0) {
+		(void) fprintf(stderr, "paa_check: realm mismatch: signed realm '%s' vs '%s'\n",
+			id->realm, realm);
+		return 0;
+	}
+	/* check timestamp is within bounds */
+	t = time(NULL);
+	if (id->timestamp < t - (3 * 60)) {
+		(void) fprintf(stderr, "paa_check: timestamp check: %lld seconds ago\n",
+			t - id->timestamp);
+		return 0;
+	}
+	if (id->timestamp > t + (3 * 60)) {
+		(void) fprintf(stderr, "paa_check: timestamp check: %lld seconds in future\n",
+			id->timestamp - t);
+		return 0;
+	}
+	return 1;
+}
+
+/* print identity details on a stream */
+int
+paa_print_identity(FILE *fp, paa_identity_t *id)
+{
+	(void) fprintf(fp, "\tuserid\t%s\n\tclient\t%s\n\trealm\t%s\n\ttime\t%.24s\n",
+		id->userid,
+		id->client,
+		id->realm,
+		ctime(&id->timestamp));
+	return 1;
+}
+
+/* utility function to write a string to a file */
+int
+paa_write_file(const char *f, char *s, unsigned cc)
+{
+	FILE	*fp;
+
+	if ((fp = fopen(f, "w")) == NULL) {
+		(void) fprintf(stderr, "can't write file '%s'\n", f);
+		return 0;
+	}
+	write(fileno(fp), s, cc);
+	(void) fclose(fp);
+	return 1;
+}
+
+/* utility function to read a string from a file */
+int
+paa_read_file(const char *f, char *s, size_t size)
+{
+	FILE	*fp;
+	int	 cc;
+
+	if ((fp = fopen(f, "r")) == NULL) {
+		(void) fprintf(stderr, "can't write '%s'\n", f);
+		return 0;
+	}
+	cc = read(fileno(fp), s, size);
+	(void) fclose(fp);
+	return cc;
+}
Index: src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.h
diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.h:1.1
--- /dev/null	Fri Sep 10 05:15:16 2010
+++ src/crypto/external/bsd/netpgp/dist/src/libpaa/libpaa.h	Fri Sep 10 05:15:16 2010
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2010 Alistair Crooks <a...@netbsd.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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 LIBPAA_H_
+#define LIBPAA_H_	20100908
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#define DEFAULT_HASH_ALG "SHA256"
+
+enum {
+	PAA_CHALLENGE_SIZE	= 128
+};
+
+/* constant and secret info for server side */
+typedef struct paa_server_info_t {
+	char		 hostaddress[128];		/* host ip address */
+	char		*secret;			/* raw secret of server */
+	unsigned	 secretc;			/* # of characters used */
+	char		 server_signature[512];		/* this is the encoded signature */
+	int		 server_signaturec;		/* # of chars in encoded sig */
+} paa_server_info_t;
+
+/* used in server to formulate challenge */
+typedef struct paa_challenge_t {
+	const char	*realm;				/* this is realm of challenge */
+	const char	*domain;			/* domain of challenge */
+	char		 challenge[512];		/* the output challenge */
+	int		 challengec;			/* # of chars in challenge */
+	/* sub-parts of challenge */
+	char		 encoded_challenge[512];	/* encoded challenge part */
+	int		 encc;				/* # of chars in encoded challenge */
+} paa_challenge_t;
+
+/* used in client to formulate response */
+typedef struct paa_response_t {
+	const char	*userid;			/* identity to be used for signature */
+	const char	*realm;				/* realm that client wants */
+	char		 challenge[PAA_CHALLENGE_SIZE];	/* input challenge */
+	int		 challengec;			/* # if chars in input */
+	char		 response[PAA_CHALLENGE_SIZE * 2];	/* output response */
+	int		 respc;				/* # of chars in output */
+} paa_response_t;
+
+/* this struct holds the identity information in the paa response */
+typedef struct paa_identity_t {
+	char		 userid[32];		/* verified identity */
+	char		 client[128];		/* client address */
+	char		 realm[128];		/* client realm */
+	char		 domain[128];		/* client domain */
+	int64_t		 timestamp;		/* time of response */
+} paa_identity_t;
+
+/* support functions */
+int paa_write_file(const char *, char *, unsigned);
+int paa_read_file(const char *, char *, size_t);
+
+/* server initialisations - one time */
+int paa_server_init(paa_server_info_t *, unsigned);
+
+/* body of pubkey access authentication challenge/response/check functionality */
+int paa_format_challenge(paa_challenge_t *, paa_server_info_t *, char *, size_t);
+int paa_format_response(paa_response_t *, netpgp_t *, char *, char *, size_t);
+int paa_check_response(paa_challenge_t *, paa_identity_t *, netpgp_t *, char *);
+
+/* who are ya? */
+int paa_print_identity(FILE *, paa_identity_t *);
+
+#endif
Index: src/crypto/external/bsd/netpgp/dist/src/libpaa/server.c
diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libpaa/server.c:1.1
--- /dev/null	Fri Sep 10 05:15:16 2010
+++ src/crypto/external/bsd/netpgp/dist/src/libpaa/server.c	Fri Sep 10 05:15:16 2010
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2010 Alistair Crooks <a...@netbsd.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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 <sys/types.h>
+
+#include <netdb.h>
+
+#include <netpgp.h>
+#include <regex.h>
+#include <sha1.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "libpaa.h"
+
+#define DEFAULT_HASH_ALG "SHA256"
+
+int
+main(int argc, char **argv)
+{
+	paa_server_info_t	server;
+	paa_challenge_t		challenge;
+	paa_identity_t		id;
+	netpgp_t		netpgp;
+	char			buf[2048];
+	int			secretc;
+	int			cc;
+	int			i;
+
+	(void) memset(&server, 0x0, sizeof(server));
+	(void) memset(&challenge, 0x0, sizeof(challenge));
+	(void) memset(&id, 0x0, sizeof(id));
+	(void) memset(&netpgp, 0x0, sizeof(netpgp));
+	secretc = 64;
+	while ((i = getopt(argc, argv, "S:c:d:r:u:")) != -1) {
+		switch(i) {
+		case 'S':
+			netpgp_setvar(&netpgp, "ssh keys", "1");
+			netpgp_setvar(&netpgp, "sshkeyfile", optarg);
+			break;
+		case 'c':
+			secretc = atoi(optarg);
+			break;
+		case 'd':
+			challenge.domain = optarg;
+			break;
+		case 'r':
+			challenge.realm = optarg;
+			break;
+		case 'u':
+			netpgp_setvar(&netpgp, "userid", optarg);
+			break;
+		}
+	}
+	netpgp_setvar(&netpgp, "hash", DEFAULT_HASH_ALG);
+	netpgp_setvar(&netpgp, "need seckey", "1");
+	netpgp_setvar(&netpgp, "need userid", "1");
+	netpgp_set_homedir(&netpgp, getenv("HOME"),
+			netpgp_getvar(&netpgp, "ssh keys") ? "/.ssh" : "/.gnupg", 1);
+	if (!netpgp_init(&netpgp)) {
+		(void) fprintf(stderr, "can't initialise netpgp\n");
+		exit(EXIT_FAILURE);
+	}
+	if (!paa_server_init(&server, secretc)) {
+		(void) fprintf(stderr, "can't initialise paa server\n");
+		exit(EXIT_FAILURE);
+	}
+	/* format the challenge */
+	cc = paa_format_challenge(&challenge, &server, buf, sizeof(buf));
+	/* write challenge to temp file */
+	paa_write_file("challenge", buf, cc);
+	/* get the client to authenticate via paa, writing to temp response file */
+	system("clnt/paaclient -r authenticat...@bigco.com < challenge > response");
+	/* read in response */
+	cc = paa_read_file("response", buf, sizeof(buf));
+	if (!paa_check_response(&challenge, &id, &netpgp, buf)) {
+		(void) fprintf(stderr, "server: paa_check failed\n");
+		exit(EXIT_FAILURE);
+	}
+	printf("paa_check_response verified challenge: signature authenticated:\n");
+	paa_print_identity(stdout, &id);
+	printf("Changing buf[%d] from '%c' to '%c'\n", cc / 2, buf[cc / 2], buf[cc / 2] - 1);
+	buf[cc / 2] = buf[cc / 2] - 1;
+	if (paa_check_response(&challenge, &id, &netpgp, buf)) {
+		(void) fprintf(stderr, "server: unexpected paa_check pass\n");
+		exit(EXIT_FAILURE);
+	}
+	printf("paa_check_response verified challenge: signature not authenticated:\n");
+	exit(EXIT_SUCCESS);
+}

Reply via email to