xref: /openbsd-src/sbin/isakmpd/prf.c (revision 82bad92d22350e34329aa62caabc59c254f928fb)
1 /* $OpenBSD: prf.c,v 1.16 2013/03/21 04:30:14 deraadt Exp $	 */
2 /* $EOM: prf.c,v 1.7 1999/05/02 12:50:29 niklas Exp $	 */
3 
4 /*
5  * Copyright (c) 1998 Niels Provos.  All rights reserved.
6  * Copyright (c) 1999 Niklas Hallqvist.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * This code was written under funding by Ericsson Radio Systems.
31  */
32 
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "hash.h"
37 #include "log.h"
38 #include "prf.h"
39 
40 void	prf_hash_init(struct prf_hash_ctx *);
41 void	prf_hash_update(struct prf_hash_ctx *, unsigned char *, unsigned int);
42 void	prf_hash_final(unsigned char *, struct prf_hash_ctx *);
43 
44 /* PRF behaves likes a hash */
45 
46 void
prf_hash_init(struct prf_hash_ctx * ctx)47 prf_hash_init(struct prf_hash_ctx *ctx)
48 {
49 	memcpy(ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize);
50 	memcpy(ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize);
51 }
52 
53 void
prf_hash_update(struct prf_hash_ctx * ctx,unsigned char * data,unsigned int len)54 prf_hash_update(struct prf_hash_ctx *ctx, unsigned char *data,
55     unsigned int len)
56 {
57 	ctx->hash->Update(ctx->hash->ctx, data, len);
58 }
59 
60 void
prf_hash_final(unsigned char * digest,struct prf_hash_ctx * ctx)61 prf_hash_final(unsigned char *digest, struct prf_hash_ctx *ctx)
62 {
63 	ctx->hash->HMACFinal(digest, ctx->hash);
64 }
65 
66 /*
67  * Obtain a Pseudo-Random Function for us. At the moment this is
68  * the HMAC version of a hash. See RFC-2104 for reference.
69  */
70 struct prf *
prf_alloc(enum prfs type,int subtype,unsigned char * shared,unsigned int sharedsize)71 prf_alloc(enum prfs type, int subtype, unsigned char *shared,
72     unsigned int sharedsize)
73 {
74 	struct hash    *hash;
75 	struct prf     *prf;
76 	struct prf_hash_ctx *prfctx;
77 
78 	switch (type) {
79 	case PRF_HMAC:
80 		hash = hash_get(subtype);
81 		if (!hash) {
82 			log_print("prf_alloc: unknown hash type %d", subtype);
83 			return 0;
84 		}
85 		break;
86 	default:
87 		log_print("prf_alloc: unknown PRF type %d", type);
88 		return 0;
89 	}
90 
91 	prf = malloc(sizeof *prf);
92 	if (!prf) {
93 		log_error("prf_alloc: malloc (%lu) failed",
94 		    (unsigned long)sizeof *prf);
95 		return 0;
96 	}
97 	if (type == PRF_HMAC) {
98 		/* Obtain needed memory.  */
99 		prfctx = malloc(sizeof *prfctx);
100 		if (!prfctx) {
101 			log_error("prf_alloc: malloc (%lu) failed",
102 			    (unsigned long)sizeof *prfctx);
103 			goto cleanprf;
104 		}
105 		prf->prfctx = prfctx;
106 
107 		prfctx->ctx = malloc(hash->ctxsize);
108 		if (!prfctx->ctx) {
109 			log_error("prf_alloc: malloc (%d) failed",
110 			    hash->ctxsize);
111 			goto cleanprfctx;
112 		}
113 		prfctx->ctx2 = malloc(hash->ctxsize);
114 		if (!prfctx->ctx2) {
115 			log_error("prf_alloc: malloc (%d) failed",
116 			    hash->ctxsize);
117 			free(prfctx->ctx);
118 			goto cleanprfctx;
119 		}
120 		prf->type = PRF_HMAC;
121 		prf->blocksize = hash->hashsize;
122 		prfctx->hash = hash;
123 
124 		/* Use the correct function pointers.  */
125 		prf->Init = (void(*)(void *))prf_hash_init;
126 		prf->Update = (void(*)(void *, unsigned char *,
127 		    unsigned int))prf_hash_update;
128 		prf->Final = (void(*)(unsigned char *, void *))prf_hash_final;
129 
130 		/* Init HMAC contexts.  */
131 		hash->HMACInit(hash, shared, sharedsize);
132 
133 		/* Save contexts.  */
134 		memcpy(prfctx->ctx, hash->ctx, hash->ctxsize);
135 		memcpy(prfctx->ctx2, hash->ctx2, hash->ctxsize);
136 	}
137 	return prf;
138 
139 cleanprfctx:
140 	free(prf->prfctx);
141 cleanprf:
142 	free(prf);
143 	return 0;
144 }
145 
146 /* Deallocate the PRF pointed to by PRF.  */
147 void
prf_free(struct prf * prf)148 prf_free(struct prf *prf)
149 {
150 	struct prf_hash_ctx *prfctx = prf->prfctx;
151 
152 	if (prf->type == PRF_HMAC) {
153 		free(prfctx->ctx2);
154 		free(prfctx->ctx);
155 	}
156 	free(prf->prfctx);
157 	free(prf);
158 }
159