blob: 1987e4d4fbd089581f1876bcf8979c0d8a59927d [file] [log] [blame]
/* $NetBSD: prsa_par.y,v 1.6 2011/03/02 14:49:21 vanhu Exp $ */
/* Id: prsa_par.y,v 1.3 2004/11/08 12:04:23 ludvigm Exp */
%{
/*
* Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
* Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs
* 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.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
*/
/* This file contains a parser for FreeS/WAN-style ipsec.secrets RSA keys. */
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include "misc.h"
#include "vmbuf.h"
#include "plog.h"
#include "oakley.h"
#include "isakmp_var.h"
#include "handler.h"
#include "crypto_openssl.h"
#include "sockmisc.h"
#include "rsalist.h"
extern void prsaerror(const char *str, ...);
extern int prsawrap (void);
extern int prsalex (void);
extern char *prsatext;
extern int prsa_cur_lineno;
extern char *prsa_cur_fname;
extern FILE *prsain;
int prsa_cur_lineno = 0;
char *prsa_cur_fname = NULL;
struct genlist *prsa_cur_list = NULL;
enum rsa_key_type prsa_cur_type = RSA_TYPE_ANY;
static RSA *rsa_cur;
void
prsaerror(const char *s, ...)
{
char fmt[512];
va_list ap;
#ifdef HAVE_STDARG_H
va_start(ap, s);
#else
va_start(ap);
#endif
snprintf(fmt, sizeof(fmt), "%s:%d: %s",
prsa_cur_fname, prsa_cur_lineno, s);
plogv(LLV_ERROR, LOCATION, NULL, fmt, ap);
va_end(ap);
}
void
prsawarning(const char *s, ...)
{
char fmt[512];
va_list ap;
#ifdef HAVE_STDARG_H
va_start(ap, s);
#else
va_start(ap);
#endif
snprintf(fmt, sizeof(fmt), "%s:%d: %s",
prsa_cur_fname, prsa_cur_lineno, s);
plogv(LLV_WARNING, LOCATION, NULL, fmt, ap);
va_end(ap);
}
int
prsawrap()
{
return 1;
}
%}
%union {
BIGNUM *bn;
RSA *rsa;
char *chr;
long num;
struct netaddr *naddr;
}
%token COLON HEX
%token OBRACE EBRACE COLON HEX
%token TAG_RSA TAG_PUB TAG_PSK
%token MODULUS PUBLIC_EXPONENT PRIVATE_EXPONENT
%token PRIME1 PRIME2 EXPONENT1 EXPONENT2 COEFFICIENT
%token ADDR4 ADDR6 ADDRANY SLASH NUMBER BASE64
%type <bn> HEX
%type <num> NUMBER
%type <chr> ADDR4 ADDR6 BASE64
%type <rsa> rsa_statement
%type <num> prefix
%type <naddr> addr4 addr6 addr
%%
statements:
statements statement
| statement
;
statement:
addr addr COLON rsa_statement
{
rsa_key_insert(prsa_cur_list, $1, $2, $4);
}
| addr COLON rsa_statement
{
rsa_key_insert(prsa_cur_list, NULL, $1, $3);
}
| COLON rsa_statement
{
rsa_key_insert(prsa_cur_list, NULL, NULL, $2);
}
;
rsa_statement:
TAG_RSA OBRACE params EBRACE
{
if (prsa_cur_type == RSA_TYPE_PUBLIC) {
prsawarning("Using private key for public key purpose.\n");
if (!rsa_cur->n || !rsa_cur->e) {
prsaerror("Incomplete key. Mandatory parameters are missing!\n");
YYABORT;
}
}
else {
if (!rsa_cur->n || !rsa_cur->e || !rsa_cur->d) {
prsaerror("Incomplete key. Mandatory parameters are missing!\n");
YYABORT;
}
if (!rsa_cur->p || !rsa_cur->q || !rsa_cur->dmp1
|| !rsa_cur->dmq1 || !rsa_cur->iqmp) {
if (rsa_cur->p) BN_clear_free(rsa_cur->p);
if (rsa_cur->q) BN_clear_free(rsa_cur->q);
if (rsa_cur->dmp1) BN_clear_free(rsa_cur->dmp1);
if (rsa_cur->dmq1) BN_clear_free(rsa_cur->dmq1);
if (rsa_cur->iqmp) BN_clear_free(rsa_cur->iqmp);
rsa_cur->p = NULL;
rsa_cur->q = NULL;
rsa_cur->dmp1 = NULL;
rsa_cur->dmq1 = NULL;
rsa_cur->iqmp = NULL;
}
}
$$ = rsa_cur;
rsa_cur = RSA_new();
}
| TAG_PUB BASE64
{
if (prsa_cur_type == RSA_TYPE_PRIVATE) {
prsaerror("Public key in private-key file!\n");
YYABORT;
}
$$ = base64_pubkey2rsa($2);
free($2);
}
| TAG_PUB HEX
{
if (prsa_cur_type == RSA_TYPE_PRIVATE) {
prsaerror("Public key in private-key file!\n");
YYABORT;
}
$$ = bignum_pubkey2rsa($2);
}
;
addr:
addr4
| addr6
| ADDRANY
{
$$ = NULL;
}
;
addr4:
ADDR4 prefix
{
int err;
struct sockaddr_in *sap;
struct addrinfo hints, *res;
if ($2 == -1) $2 = 32;
if ($2 < 0 || $2 > 32) {
prsaerror ("Invalid IPv4 prefix\n");
YYABORT;
}
$$ = calloc (sizeof(struct netaddr), 1);
$$->prefix = $2;
sap = (struct sockaddr_in *)(&$$->sa);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_NUMERICHOST;
err = getaddrinfo($1, NULL, &hints, &res);
if (err < 0) {
prsaerror("getaddrinfo(%s): %s\n", $1, gai_strerror(err));
YYABORT;
}
memcpy(sap, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
free($1);
}
;
addr6:
ADDR6 prefix
{
int err;
struct sockaddr_in6 *sap;
struct addrinfo hints, *res;
if ($2 == -1) $2 = 128;
if ($2 < 0 || $2 > 128) {
prsaerror ("Invalid IPv6 prefix\n");
YYABORT;
}
$$ = calloc (sizeof(struct netaddr), 1);
$$->prefix = $2;
sap = (struct sockaddr_in6 *)(&$$->sa);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_NUMERICHOST;
err = getaddrinfo($1, NULL, &hints, &res);
if (err < 0) {
prsaerror("getaddrinfo(%s): %s\n", $1, gai_strerror(err));
YYABORT;
}
memcpy(sap, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
free($1);
}
;
prefix:
/* nothing */ { $$ = -1; }
| SLASH NUMBER { $$ = $2; }
;
params:
params param
| param
;
param:
MODULUS COLON HEX
{ if (!rsa_cur->n) rsa_cur->n = $3; else { prsaerror ("Modulus already defined\n"); YYABORT; } }
| PUBLIC_EXPONENT COLON HEX
{ if (!rsa_cur->e) rsa_cur->e = $3; else { prsaerror ("PublicExponent already defined\n"); YYABORT; } }
| PRIVATE_EXPONENT COLON HEX
{ if (!rsa_cur->d) rsa_cur->d = $3; else { prsaerror ("PrivateExponent already defined\n"); YYABORT; } }
| PRIME1 COLON HEX
{ if (!rsa_cur->p) rsa_cur->p = $3; else { prsaerror ("Prime1 already defined\n"); YYABORT; } }
| PRIME2 COLON HEX
{ if (!rsa_cur->q) rsa_cur->q = $3; else { prsaerror ("Prime2 already defined\n"); YYABORT; } }
| EXPONENT1 COLON HEX
{ if (!rsa_cur->dmp1) rsa_cur->dmp1 = $3; else { prsaerror ("Exponent1 already defined\n"); YYABORT; } }
| EXPONENT2 COLON HEX
{ if (!rsa_cur->dmq1) rsa_cur->dmq1 = $3; else { prsaerror ("Exponent2 already defined\n"); YYABORT; } }
| COEFFICIENT COLON HEX
{ if (!rsa_cur->iqmp) rsa_cur->iqmp = $3; else { prsaerror ("Coefficient already defined\n"); YYABORT; } }
;
%%
int prsaparse(void);
int
prsa_parse_file(struct genlist *list, char *fname, enum rsa_key_type type)
{
FILE *fp = NULL;
int ret;
if (!fname)
return -1;
if (type == RSA_TYPE_PRIVATE) {
struct stat st;
if (stat(fname, &st) < 0)
return -1;
if (st.st_mode & (S_IRWXG | S_IRWXO)) {
plog(LLV_ERROR, LOCATION, NULL,
"Too slack permissions on private key '%s'\n",
fname);
plog(LLV_ERROR, LOCATION, NULL,
"Should be at most 0600, now is 0%o\n",
st.st_mode & 0777);
return -1;
}
}
fp = fopen(fname, "r");
if (!fp)
return -1;
prsain = fp;
prsa_cur_lineno = 1;
prsa_cur_fname = fname;
prsa_cur_list = list;
prsa_cur_type = type;
rsa_cur = RSA_new();
ret = prsaparse();
if (rsa_cur) {
RSA_free(rsa_cur);
rsa_cur = NULL;
}
fclose (fp);
prsain = NULL;
return ret;
}