2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31 * All rights reserved.
32 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33 * their moral rights under the UK Copyright Design and Patents Act 1988 to
34 * be recorded as the authors of this copyright work.
36 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37 * use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 * http://www.apache.org/licenses/LICENSE-2.0
42 * Unless required by applicable law or agreed to in writing, software
43 * distributed under the License is distributed on an "AS IS" BASIS,
44 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
54 #ifdef HAVE_SYS_CDEFS_H
55 #include <sys/cdefs.h>
58 #if defined(__NetBSD__)
59 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
60 __RCSID("$NetBSD: create.c,v 1.20 2009/10/06 02:26:05 agc Exp $");
63 #include <sys/types.h>
64 #include <sys/param.h>
77 #ifdef HAVE_OPENSSL_CAST_H
78 #include <openssl/cast.h>
84 #include "signature.h"
86 #include "readerwriter.h"
88 #include "netpgpdefs.h"
89 #include "netpgpdigest.h"
92 * \ingroup Core_Create
96 * \return 1 if OK, otherwise 0
100 __ops_write_ss_header(__ops_output_t
*output
,
102 __ops_content_tag_t type
)
104 return __ops_write_length(output
, length
) &&
105 __ops_write_scalar(output
, (unsigned)(type
-
106 (unsigned)OPS_PTAG_SIG_SUBPKT_BASE
), 1);
110 * XXX: the general idea of _fast_ is that it doesn't copy stuff the safe
111 * (i.e. non _fast_) version will, and so will also need to be freed.
115 * \ingroup Core_Create
117 * __ops_fast_create_userid() sets id->userid to the given userid.
118 * This is fast because it is only copying a char*. However, if userid
119 * is changed or freed in the future, this could have injurious results.
125 __ops_fast_create_userid(__ops_userid_t
*id
, unsigned char *userid
)
131 * \ingroup Core_WritePackets
132 * \brief Writes a User Id packet
135 * \return 1 if OK, otherwise 0
138 __ops_write_struct_userid(__ops_output_t
*output
, __ops_userid_t
*id
)
140 return __ops_write_ptag(output
, OPS_PTAG_CT_USER_ID
) &&
141 __ops_write_length(output
, strlen((char *) id
->userid
)) &&
142 __ops_write(output
, id
->userid
, strlen((char *) id
->userid
));
146 * \ingroup Core_WritePackets
147 * \brief Write a User Id packet.
151 * \return return value from __ops_write_struct_userid()
154 __ops_write_userid(const unsigned char *userid
, __ops_output_t
*output
)
158 id
.userid
= __UNCONST(userid
);
159 return __ops_write_struct_userid(output
, &id
);
166 mpi_length(const BIGNUM
*bn
)
168 return (unsigned)(2 + (BN_num_bits(bn
) + 7) / 8);
172 pubkey_length(const __ops_pubkey_t
*key
)
176 return mpi_length(key
->key
.rsa
.n
) + mpi_length(key
->key
.rsa
.e
);
179 (void) fprintf(stderr
,
180 "pubkey_length: unknown key algorithm\n");
186 seckey_length(const __ops_seckey_t
*key
)
191 switch (key
->pubkey
.alg
) {
193 len
= mpi_length(key
->key
.rsa
.d
) + mpi_length(key
->key
.rsa
.p
) +
194 mpi_length(key
->key
.rsa
.q
) + mpi_length(key
->key
.rsa
.u
);
196 return (unsigned)(len
+ pubkey_length(&key
->pubkey
));
198 (void) fprintf(stderr
,
199 "seckey_length: unknown key algorithm\n");
205 * \ingroup Core_Create
212 __ops_fast_create_rsa_pubkey(__ops_pubkey_t
*key
, time_t t
,
213 BIGNUM
*n
, BIGNUM
*e
)
215 key
->version
= OPS_V4
;
217 key
->alg
= OPS_PKA_RSA
;
223 * Note that we support v3 keys here because they're needed for for
224 * verification - the writer doesn't allow them, though
227 write_pubkey_body(const __ops_pubkey_t
*key
, __ops_output_t
*output
)
229 if (!(__ops_write_scalar(output
, (unsigned)key
->version
, 1) &&
230 __ops_write_scalar(output
, (unsigned)key
->birthtime
, 4))) {
234 if (key
->version
!= 4 &&
235 !__ops_write_scalar(output
, key
->days_valid
, 2)) {
239 if (!__ops_write_scalar(output
, (unsigned)key
->alg
, 1)) {
245 return __ops_write_mpi(output
, key
->key
.dsa
.p
) &&
246 __ops_write_mpi(output
, key
->key
.dsa
.q
) &&
247 __ops_write_mpi(output
, key
->key
.dsa
.g
) &&
248 __ops_write_mpi(output
, key
->key
.dsa
.y
);
251 case OPS_PKA_RSA_ENCRYPT_ONLY
:
252 case OPS_PKA_RSA_SIGN_ONLY
:
253 return __ops_write_mpi(output
, key
->key
.rsa
.n
) &&
254 __ops_write_mpi(output
, key
->key
.rsa
.e
);
256 case OPS_PKA_ELGAMAL
:
257 return __ops_write_mpi(output
, key
->key
.elgamal
.p
) &&
258 __ops_write_mpi(output
, key
->key
.elgamal
.g
) &&
259 __ops_write_mpi(output
, key
->key
.elgamal
.y
);
262 (void) fprintf(stderr
,
263 "write_pubkey_body: bad algorithm\n");
270 * Note that we support v3 keys here because they're needed for
271 * verification - the writer doesn't allow them, though
274 write_seckey_body(const __ops_seckey_t
*key
,
275 const unsigned char *passphrase
,
277 __ops_output_t
*output
)
279 /* RFC4880 Section 5.5.3 Secret-Key Packet Formats */
281 __ops_crypt_t crypted
;
283 unsigned char hashed
[OPS_SHA1_HASH_SIZE
];
284 unsigned char sesskey
[CAST_KEY_LENGTH
];
285 unsigned int done
= 0;
288 if (!write_pubkey_body(&key
->pubkey
, output
)) {
291 if (key
->s2k_usage
!= OPS_S2KU_ENCRYPTED_AND_HASHED
) {
292 (void) fprintf(stderr
, "write_seckey_body: s2k usage\n");
295 if (!__ops_write_scalar(output
, (unsigned)key
->s2k_usage
, 1)) {
299 if (key
->alg
!= OPS_SA_CAST5
) {
300 (void) fprintf(stderr
, "write_seckey_body: algorithm\n");
303 if (!__ops_write_scalar(output
, (unsigned)key
->alg
, 1)) {
307 if (key
->s2k_specifier
!= OPS_S2KS_SIMPLE
&&
308 key
->s2k_specifier
!= OPS_S2KS_SALTED
) {
309 /* = 1 \todo could also be iterated-and-salted */
310 (void) fprintf(stderr
, "write_seckey_body: s2k spec\n");
313 if (!__ops_write_scalar(output
, (unsigned)key
->s2k_specifier
, 1)) {
317 if (key
->hash_alg
!= OPS_HASH_SHA1
) {
318 (void) fprintf(stderr
, "write_seckey_body: hash alg\n");
321 if (!__ops_write_scalar(output
, (unsigned)key
->hash_alg
, 1)) {
325 switch (key
->s2k_specifier
) {
326 case OPS_S2KS_SIMPLE
:
327 /* nothing more to do */
330 case OPS_S2KS_SALTED
:
331 /* 8-octet salt value */
332 __ops_random(__UNCONST(&key
->salt
[0]), OPS_SALT_SIZE
);
333 if (!__ops_write(output
, key
->salt
, OPS_SALT_SIZE
)) {
339 * \todo case OPS_S2KS_ITERATED_AND_SALTED: // 8-octet salt
340 * value // 1-octet count break;
344 (void) fprintf(stderr
,
345 "invalid/unsupported s2k specifier %d\n",
350 if (!__ops_write(output
, &key
->iv
[0], __ops_block_size(key
->alg
))) {
355 * create the session key for encrypting the algorithm-specific
359 switch (key
->s2k_specifier
) {
360 case OPS_S2KS_SIMPLE
:
361 case OPS_S2KS_SALTED
:
362 /* RFC4880: section 3.7.1.1 and 3.7.1.2 */
364 for (done
= 0, i
= 0; done
< CAST_KEY_LENGTH
; i
++) {
365 unsigned char zero
= 0;
370 needed
= CAST_KEY_LENGTH
- done
;
371 size
= MIN(needed
, OPS_SHA1_HASH_SIZE
);
373 __ops_hash_any(&hash
, key
->hash_alg
);
374 if (!hash
.init(&hash
)) {
375 (void) fprintf(stderr
, "write_seckey_body: bad alloc\n");
379 /* preload if iterating */
380 for (j
= 0; j
< i
; j
++) {
382 * Coverity shows a DEADCODE error on this
383 * line. This is expected since the hardcoded
384 * use of SHA1 and CAST5 means that it will
385 * not used. This will change however when
386 * other algorithms are supported.
388 hash
.add(&hash
, &zero
, 1);
391 if (key
->s2k_specifier
== OPS_S2KS_SALTED
) {
392 hash
.add(&hash
, key
->salt
, OPS_SALT_SIZE
);
394 hash
.add(&hash
, passphrase
, pplen
);
395 hash
.finish(&hash
, hashed
);
398 * if more in hash than is needed by session key, use
399 * the leftmost octets
401 (void) memcpy(&sesskey
[i
* OPS_SHA1_HASH_SIZE
],
402 hashed
, (unsigned)size
);
403 done
+= (unsigned)size
;
404 if (done
> CAST_KEY_LENGTH
) {
405 (void) fprintf(stderr
,
406 "write_seckey_body: short add\n");
414 * \todo case OPS_S2KS_ITERATED_AND_SALTED: * 8-octet salt
415 * value * 1-octet count break;
419 (void) fprintf(stderr
,
420 "invalid/unsupported s2k specifier %d\n",
425 /* use this session key to encrypt */
427 __ops_crypt_any(&crypted
, key
->alg
);
428 crypted
.set_iv(&crypted
, key
->iv
);
429 crypted
.set_crypt_key(&crypted
, sesskey
);
430 __ops_encrypt_init(&crypted
);
432 if (__ops_get_debug_level(__FILE__
)) {
435 (void) fprintf(stderr
, "\nWRITING:\niv=");
436 for (i2
= 0; i2
< __ops_block_size(key
->alg
); i2
++) {
437 (void) fprintf(stderr
, "%02x ", key
->iv
[i2
]);
439 (void) fprintf(stderr
, "\n");
441 (void) fprintf(stderr
, "key=");
442 for (i2
= 0; i2
< CAST_KEY_LENGTH
; i2
++) {
443 (void) fprintf(stderr
, "%02x ", sesskey
[i2
]);
445 (void) fprintf(stderr
, "\n");
447 (void) fprintf(stderr
, "turning encryption on...\n");
449 __ops_push_enc_crypt(output
, &crypted
);
451 switch (key
->pubkey
.alg
) {
452 /* case OPS_PKA_DSA: */
453 /* return __ops_write_mpi(output, key->key.dsa.x); */
456 case OPS_PKA_RSA_ENCRYPT_ONLY
:
457 case OPS_PKA_RSA_SIGN_ONLY
:
459 if (!__ops_write_mpi(output
, key
->key
.rsa
.d
) ||
460 !__ops_write_mpi(output
, key
->key
.rsa
.p
) ||
461 !__ops_write_mpi(output
, key
->key
.rsa
.q
) ||
462 !__ops_write_mpi(output
, key
->key
.rsa
.u
)) {
463 if (__ops_get_debug_level(__FILE__
)) {
464 (void) fprintf(stderr
,
465 "4 x mpi not written - problem\n");
471 /* case OPS_PKA_ELGAMAL: */
472 /* return __ops_write_mpi(output, key->key.elgamal.x); */
478 if (!__ops_write(output
, key
->checkhash
, OPS_CHECKHASH_SIZE
)) {
482 __ops_writer_pop(output
);
488 * \ingroup Core_WritePackets
489 * \brief Writes a Public Key packet
492 * \return 1 if OK, otherwise 0
495 write_struct_pubkey(__ops_output_t
*output
, const __ops_pubkey_t
*key
)
497 if (key
->version
!= 4) {
498 (void) fprintf(stderr
,
499 "write_struct_pubkey: wrong key version\n");
502 return __ops_write_ptag(output
, OPS_PTAG_CT_PUBLIC_KEY
) &&
503 __ops_write_length(output
, 1 + 4 + 1 + pubkey_length(key
)) &&
504 write_pubkey_body(key
, output
);
509 \ingroup HighLevel_KeyWrite
511 \brief Writes a transferable PGP public key to the given output stream.
513 \param keydata Key to be written
514 \param armoured Flag is set for armoured output
515 \param output Output stream
520 __ops_write_xfer_pubkey(__ops_output_t
*output
,
521 const __ops_key_t
*keydata
,
522 const unsigned armoured
)
527 __ops_writer_push_armoured(output
, OPS_PGP_PUBLIC_KEY_BLOCK
);
530 if (!write_struct_pubkey(output
, &keydata
->key
.seckey
.pubkey
)) {
534 /* TODO: revocation signatures go here */
536 /* user ids and corresponding signatures */
537 for (i
= 0; i
< keydata
->uidc
; i
++) {
538 __ops_userid_t
*uid
= &keydata
->uids
[i
];
540 if (!__ops_write_struct_userid(output
, uid
)) {
544 /* find signature for this packet if it exists */
545 for (j
= 0; j
< keydata
->sigc
; j
++) {
546 sigpacket_t
*sig
= &keydata
->sigs
[i
];
548 if (strcmp((char *) sig
->userid
->userid
,
549 (char *) uid
->userid
) == 0) {
550 if (!__ops_write(output
, sig
->packet
->raw
,
551 sig
->packet
->length
)) {
558 /* TODO: user attributes and corresponding signatures */
561 * subkey packets and corresponding signatures and optional
566 writer_info_finalise(&output
->errors
, &output
->writer
);
567 __ops_writer_pop(output
);
573 \ingroup HighLevel_KeyWrite
575 \brief Writes a transferable PGP secret key to the given output stream.
577 \param keydata Key to be written
580 \param armoured Flag is set for armoured output
581 \param output Output stream
586 __ops_write_xfer_seckey(__ops_output_t
*output
,
587 const __ops_key_t
*keydata
,
588 const unsigned char *passphrase
,
595 __ops_writer_push_armoured(output
, OPS_PGP_PRIVATE_KEY_BLOCK
);
598 if (!__ops_write_struct_seckey(&keydata
->key
.seckey
, passphrase
,
603 /* TODO: revocation signatures go here */
605 /* user ids and corresponding signatures */
606 for (i
= 0; i
< keydata
->uidc
; i
++) {
607 __ops_userid_t
*uid
= &keydata
->uids
[i
];
609 if (!__ops_write_struct_userid(output
, uid
)) {
613 /* find signature for this packet if it exists */
614 for (j
= 0; j
< keydata
->sigc
; j
++) {
615 sigpacket_t
*sig
= &keydata
->sigs
[i
];
617 if (strcmp((char *) sig
->userid
->userid
,
618 (char *) uid
->userid
) == 0) {
619 if (!__ops_write(output
, sig
->packet
->raw
,
620 sig
->packet
->length
)) {
627 /* TODO: user attributes and corresponding signatures */
630 * subkey packets and corresponding signatures and optional
635 writer_info_finalise(&output
->errors
, &output
->writer
);
636 __ops_writer_pop(output
);
642 * \ingroup Core_WritePackets
643 * \brief Writes one RSA public key packet.
644 * \param t Creation time
645 * \param n RSA public modulus
646 * \param e RSA public encryption exponent
647 * \param output Writer settings
649 * \return 1 if OK, otherwise 0
653 __ops_write_rsa_pubkey(time_t t
, const BIGNUM
*n
,
655 __ops_output_t
*output
)
659 __ops_fast_create_rsa_pubkey(&key
, t
, __UNCONST(n
), __UNCONST(e
));
660 return write_struct_pubkey(output
, &key
);
664 * \ingroup Core_Create
671 __ops_build_pubkey(__ops_memory_t
*out
, const __ops_pubkey_t
*key
,
672 unsigned make_packet
)
674 __ops_output_t
*output
;
676 output
= __ops_output_new();
677 __ops_memory_init(out
, 128);
678 __ops_writer_set_memory(output
, out
);
679 write_pubkey_body(key
, output
);
681 __ops_memory_make_packet(out
, OPS_PTAG_CT_PUBLIC_KEY
);
683 __ops_output_delete(output
);
687 * \ingroup Core_Create
689 * Create an RSA secret key structure. If a parameter is marked as
690 * [OPTIONAL], then it can be omitted and will be calculated from
691 * other params - or, in the case of e, will default to 0x10001.
693 * Parameters are _not_ copied, so will be freed if the structure is
696 * \param key The key structure to be initialised.
698 * \param d The RSA parameter d (=e^-1 mod (p-1)(q-1)) [OPTIONAL]
699 * \param p The RSA parameter p
700 * \param q The RSA parameter q (q > p)
701 * \param u The RSA parameter u (=p^-1 mod q) [OPTIONAL]
702 * \param n The RSA public parameter n (=p*q) [OPTIONAL]
703 * \param e The RSA public parameter e */
706 __ops_fast_create_rsa_seckey(__ops_seckey_t
*key
, time_t t
,
707 BIGNUM
*d
, BIGNUM
*p
, BIGNUM
*q
, BIGNUM
*u
,
708 BIGNUM
*n
, BIGNUM
*e
)
710 __ops_fast_create_rsa_pubkey(&key
->pubkey
, t
, n
, e
);
712 /* XXX: calculate optionals */
718 key
->s2k_usage
= OPS_S2KU_NONE
;
720 /* XXX: sanity check and add errors... */
724 * \ingroup Core_WritePackets
725 * \brief Writes a Secret Key packet.
726 * \param key The secret key
727 * \param passphrase The passphrase
728 * \param pplen Length of passphrase
730 * \return 1 if OK; else 0
733 __ops_write_struct_seckey(const __ops_seckey_t
*key
,
734 const unsigned char *passphrase
,
736 __ops_output_t
*output
)
740 if (key
->pubkey
.version
!= 4) {
741 (void) fprintf(stderr
,
742 "__ops_write_struct_seckey: public key version\n");
746 /* Ref: RFC4880 Section 5.5.3 */
748 /* pubkey, excluding MPIs */
749 length
+= 1 + 4 + 1 + 1;
754 switch (key
->s2k_usage
) {
759 case OPS_S2KU_ENCRYPTED_AND_HASHED
: /* 254 */
760 case OPS_S2KU_ENCRYPTED
: /* 255 */
762 /* Ref: RFC4880 Section 3.7 */
763 length
+= 1; /* s2k_specifier */
765 switch (key
->s2k_specifier
) {
766 case OPS_S2KS_SIMPLE
:
767 length
+= 1; /* hash algorithm */
770 case OPS_S2KS_SALTED
:
771 length
+= 1 + 8; /* hash algorithm + salt */
774 case OPS_S2KS_ITERATED_AND_SALTED
:
775 length
+= 1 + 8 + 1; /* hash algorithm, salt +
780 (void) fprintf(stderr
,
781 "__ops_write_struct_seckey: s2k spec\n");
787 (void) fprintf(stderr
,
788 "__ops_write_struct_seckey: s2k usage\n");
793 if (key
->s2k_usage
) {
794 length
+= __ops_block_size(key
->alg
);
796 /* checksum or hash */
797 switch (key
->s2k_usage
) {
799 case OPS_S2KU_ENCRYPTED
:
803 case OPS_S2KU_ENCRYPTED_AND_HASHED
:
804 length
+= OPS_CHECKHASH_SIZE
;
808 (void) fprintf(stderr
,
809 "__ops_write_struct_seckey: s2k cksum usage\n");
813 /* secret key and public key MPIs */
814 length
+= (unsigned)seckey_length(key
);
816 return __ops_write_ptag(output
, OPS_PTAG_CT_SECRET_KEY
) &&
817 /* __ops_write_length(output,1+4+1+1+seckey_length(key)+2) && */
818 __ops_write_length(output
, (unsigned)length
) &&
819 write_seckey_body(key
, passphrase
, pplen
, output
);
823 * \ingroup Core_Create
825 * \brief Create a new __ops_output_t structure.
827 * \return the new structure.
828 * \note It is the responsiblity of the caller to call __ops_output_delete().
829 * \sa __ops_output_delete()
832 __ops_output_new(void)
834 return calloc(1, sizeof(__ops_output_t
));
838 * \ingroup Core_Create
839 * \brief Delete an __ops_output_t strucut and associated resources.
841 * Delete an __ops_output_t structure. If a writer is active, then
842 * that is also deleted.
844 * \param info the structure to be deleted.
847 __ops_output_delete(__ops_output_t
*output
)
849 writer_info_delete(&output
->writer
);
855 \brief Calculate the checksum for a session key
856 \param sesskey Session Key to use
857 \param cs Checksum to be written
858 \return 1 if OK; else 0
861 __ops_calc_sesskey_checksum(__ops_pk_sesskey_t
*sesskey
, unsigned char cs
[2])
863 unsigned long checksum
= 0;
866 if (!__ops_is_sa_supported(sesskey
->symm_alg
)) {
870 for (i
= 0; i
< __ops_key_size(sesskey
->symm_alg
); i
++) {
871 checksum
+= sesskey
->key
[i
];
873 checksum
= checksum
% 65536;
875 cs
[0] = (unsigned char)((checksum
>> 8) & 0xff);
876 cs
[1] = (unsigned char)(checksum
& 0xff);
878 if (__ops_get_debug_level(__FILE__
)) {
879 (void) fprintf(stderr
,"\nm buf checksum: ");
880 (void) fprintf(stderr
," %2x",cs
[0]);
881 (void) fprintf(stderr
," %2x\n",cs
[1]);
887 create_unencoded_m_buf(__ops_pk_sesskey_t
*sesskey
, unsigned char *m_buf
)
891 /* m_buf is the buffer which will be encoded in PKCS#1 block */
892 /* encoding to form the "m" value used in the */
893 /* Public Key Encrypted Session Key Packet */
895 * as defined in RFC Section 5.1 "Public-Key Encrypted Session Key
899 m_buf
[0] = sesskey
->symm_alg
;
901 if (sesskey
->symm_alg
!= OPS_SA_CAST5
) {
902 (void) fprintf(stderr
, "create_unencoded_m_buf: symm alg\n");
905 for (i
= 0; i
< CAST_KEY_LENGTH
; i
++) {
906 /* XXX - Flexelint - Warning 679: Suspicious Truncation in arithmetic expression combining with pointer */
907 m_buf
[1 + i
] = sesskey
->key
[i
];
910 return (__ops_calc_sesskey_checksum(sesskey
,
911 m_buf
+ 1 + CAST_KEY_LENGTH
));
916 \brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
921 \return 1 if OK; else 0
924 encode_m_buf(const unsigned char *M
, size_t mLen
,
925 const __ops_pubkey_t
* pubkey
,
931 /* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
933 if (pubkey
->alg
!= OPS_PKA_RSA
) {
934 (void) fprintf(stderr
, "encode_m_buf: pubkey algorithm\n");
938 k
= (unsigned)BN_num_bytes(pubkey
->key
.rsa
.n
);
940 (void) fprintf(stderr
, "encode_m_buf: message too long\n");
943 /* these two bytes defined by RFC */
947 /* add non-zero random bytes of length k - mLen -3 */
948 for (i
= 2; i
< (k
- mLen
) - 1; ++i
) {
950 __ops_random(EM
+ i
, 1);
951 } while (EM
[i
] == 0);
955 (void) fprintf(stderr
, "encode_m_buf: bad i len\n");
961 (void) memcpy(EM
+ i
, M
, mLen
);
963 if (__ops_get_debug_level(__FILE__
)) {
966 (void) fprintf(stderr
, "Encoded Message: \n");
967 for (i2
= 0; i2
< mLen
; i2
++) {
968 (void) fprintf(stderr
, "%2x ", EM
[i2
]);
970 (void) fprintf(stderr
, "\n");
977 \brief Creates an __ops_pk_sesskey_t struct from keydata
978 \param key Keydata to use
979 \return __ops_pk_sesskey_t struct
980 \note It is the caller's responsiblity to free the returned pointer
981 \note Currently hard-coded to use CAST5
982 \note Currently hard-coded to use RSA
985 __ops_create_pk_sesskey(const __ops_key_t
*key
)
988 * Creates a random session key and encrypts it for the given key
990 * Session Key is for use with a SK algo,
991 * can be any, we're hardcoding CAST5 for now
993 * Encryption used is PK,
994 * can be any, we're hardcoding RSA for now
997 #define SZ_UNENCODED_M_BUF (CAST_KEY_LENGTH + 1 + 2)
999 const __ops_pubkey_t
*pubkey
;
1000 __ops_pk_sesskey_t
*sesskey
;
1001 unsigned char unencoded_m_buf
[SZ_UNENCODED_M_BUF
];
1002 unsigned char *encoded_m_buf
;
1003 size_t sz_encoded_m_buf
;
1005 pubkey
= __ops_get_pubkey(key
);
1006 sz_encoded_m_buf
= BN_num_bytes(pubkey
->key
.rsa
.n
);
1007 if ((encoded_m_buf
= calloc(1, sz_encoded_m_buf
)) == NULL
) {
1008 (void) fprintf(stderr
,
1009 "__ops_create_pk_sesskey: can't allocate\n");
1012 if ((sesskey
= calloc(1, sizeof(*sesskey
))) == NULL
) {
1013 (void) fprintf(stderr
,
1014 "__ops_create_pk_sesskey: can't allocate\n");
1017 if (key
->type
!= OPS_PTAG_CT_PUBLIC_KEY
) {
1018 (void) fprintf(stderr
,
1019 "__ops_create_pk_sesskey: bad type\n");
1022 sesskey
->version
= OPS_PKSK_V3
;
1023 (void) memcpy(sesskey
->key_id
, key
->key_id
,
1024 sizeof(sesskey
->key_id
));
1026 if (__ops_get_debug_level(__FILE__
)) {
1029 (void) fprintf(stderr
, "Encrypting for RSA key id : ");
1030 for (i
= 0; i
< sizeof(sesskey
->key_id
); i
++) {
1031 (void) fprintf(stderr
, "%2x ", key
->key_id
[i
]);
1033 (void) fprintf(stderr
, "\n");
1035 if (key
->key
.pubkey
.alg
!= OPS_PKA_RSA
) {
1036 (void) fprintf(stderr
,
1037 "__ops_create_pk_sesskey: bad pubkey algorithm\n");
1040 sesskey
->alg
= key
->key
.pubkey
.alg
;
1042 /* \todo allow user to specify other algorithm */
1043 sesskey
->symm_alg
= OPS_SA_CAST5
;
1044 __ops_random(sesskey
->key
, CAST_KEY_LENGTH
);
1046 if (__ops_get_debug_level(__FILE__
)) {
1049 (void) fprintf(stderr
,
1050 "CAST5 session key created (len=%d):\n ",
1052 for (i
= 0; i
< CAST_KEY_LENGTH
; i
++) {
1053 (void) fprintf(stderr
, "%2x ", sesskey
->key
[i
]);
1055 (void) fprintf(stderr
, "\n");
1057 if (create_unencoded_m_buf(sesskey
, &unencoded_m_buf
[0]) == 0) {
1058 free(encoded_m_buf
);
1061 if (__ops_get_debug_level(__FILE__
)) {
1064 printf("unencoded m buf:\n");
1065 for (i
= 0; i
< SZ_UNENCODED_M_BUF
; i
++) {
1066 printf("%2x ", unencoded_m_buf
[i
]);
1070 encode_m_buf(&unencoded_m_buf
[0], SZ_UNENCODED_M_BUF
, pubkey
,
1073 /* and encrypt it */
1074 if (!__ops_rsa_encrypt_mpi(encoded_m_buf
, sz_encoded_m_buf
, pubkey
,
1075 &sesskey
->params
)) {
1076 free(encoded_m_buf
);
1079 free(encoded_m_buf
);
1084 \ingroup Core_WritePackets
1085 \brief Writes Public Key Session Key packet
1086 \param info Write settings
1087 \param pksk Public Key Session Key to write out
1088 \return 1 if OK; else 0
1091 __ops_write_pk_sesskey(__ops_output_t
*output
, __ops_pk_sesskey_t
*pksk
)
1093 /* XXX - Flexelint - Pointer parameter 'pksk' (line 1076) could be declared as pointing to const */
1095 (void) fprintf(stderr
,
1096 "__ops_write_pk_sesskey: NULL pksk\n");
1099 if (pksk
->alg
!= OPS_PKA_RSA
) {
1100 (void) fprintf(stderr
,
1101 "__ops_write_pk_sesskey: bad algorithm\n");
1105 return __ops_write_ptag(output
, OPS_PTAG_CT_PK_SESSION_KEY
) &&
1106 __ops_write_length(output
, (unsigned)(1 + 8 + 1 +
1107 BN_num_bytes(pksk
->params
.rsa
.encrypted_m
) + 2)) &&
1108 __ops_write_scalar(output
, (unsigned)pksk
->version
, 1) &&
1109 __ops_write(output
, pksk
->key_id
, 8) &&
1110 __ops_write_scalar(output
, (unsigned)pksk
->alg
, 1) &&
1111 __ops_write_mpi(output
, pksk
->params
.rsa
.encrypted_m
)
1112 /* ?? && __ops_write_scalar(output, 0, 2); */
1117 \ingroup Core_WritePackets
1118 \brief Writes MDC packet
1119 \param hashed Hash for MDC
1120 \param output Write settings
1121 \return 1 if OK; else 0
1125 __ops_write_mdc(const unsigned char *hashed
, __ops_output_t
*output
)
1128 return __ops_write_ptag(output
, OPS_PTAG_CT_MDC
) &&
1129 __ops_write_length(output
, OPS_SHA1_HASH_SIZE
) &&
1130 __ops_write(output
, hashed
, OPS_SHA1_HASH_SIZE
);
1134 \ingroup Core_WritePackets
1135 \brief Writes Literal Data packet from buffer
1136 \param data Buffer to write out
1137 \param maxlen Max length of buffer
1138 \param type Literal Data Type
1139 \param output Write settings
1140 \return 1 if OK; else 0
1143 __ops_write_litdata(__ops_output_t
*output
,
1144 const unsigned char *data
,
1146 const __ops_litdata_type_t type
)
1149 * RFC4880 does not specify a meaning for filename or date.
1150 * It is implementation-dependent.
1151 * We will not implement them.
1153 /* \todo do we need to check text data for <cr><lf> line endings ? */
1154 return __ops_write_ptag(output
, OPS_PTAG_CT_LITDATA
) &&
1155 __ops_write_length(output
, (unsigned)(1 + 1 + 4 + maxlen
)) &&
1156 __ops_write_scalar(output
, (unsigned)type
, 1) &&
1157 __ops_write_scalar(output
, 0, 1) &&
1158 __ops_write_scalar(output
, 0, 4) &&
1159 __ops_write(output
, data
, (unsigned)maxlen
);
1163 \ingroup Core_WritePackets
1164 \brief Writes Literal Data packet from contents of file
1165 \param filename Name of file to read from
1166 \param type Literal Data Type
1167 \param output Write settings
1168 \return 1 if OK; else 0
1172 __ops_fileread_litdata(const char *filename
,
1173 const __ops_litdata_type_t type
,
1174 __ops_output_t
*output
)
1176 __ops_memory_t
*mem
;
1180 mem
= __ops_memory_new();
1181 if (!__ops_mem_readfile(mem
, filename
)) {
1184 len
= __ops_mem_len(mem
);
1185 ret
= __ops_write_ptag(output
, OPS_PTAG_CT_LITDATA
) &&
1186 __ops_write_length(output
, 1 + 1 + 4 + len
) &&
1187 __ops_write_scalar(output
, (unsigned)type
, 1) &&
1188 __ops_write_scalar(output
, 0, 1) /* filename */ &&
1189 __ops_write_scalar(output
, 0, 4) /* date */ &&
1190 __ops_write(output
, __ops_mem_data(mem
), len
);
1191 __ops_memory_free(mem
);
1196 \ingroup HighLevel_General
1198 \brief Writes contents of buffer into file
1200 \param filename Filename to write to
1201 \param buf Buffer to write to file
1202 \param len Size of buffer
1203 \param overwrite Flag to set whether to overwrite an existing file
1204 \return 1 if OK; 0 if error
1208 __ops_filewrite(const char *filename
, const char *buf
,
1209 const size_t len
, const unsigned overwrite
)
1214 flags
= O_WRONLY
| O_CREAT
;
1223 fd
= open(filename
, flags
, 0600);
1225 (void) fprintf(stderr
, "can't open '%s'\n", filename
);
1228 if (write(fd
, buf
, len
) != (int)len
) {
1232 return (close(fd
) == 0);
1236 \ingroup Core_WritePackets
1237 \brief Write Symmetrically Encrypted packet
1238 \param data Data to encrypt
1239 \param len Length of data
1240 \param output Write settings
1241 \return 1 if OK; else 0
1242 \note Hard-coded to use AES256
1245 __ops_write_symm_enc_data(const unsigned char *data
,
1247 __ops_output_t
* output
)
1249 /* buffer to write encrypted data to */
1250 unsigned char *encrypted
= (unsigned char *) NULL
;
1251 __ops_crypt_t crypt_info
;
1252 size_t encrypted_sz
; /* size of encrypted data */
1255 /* \todo assume AES256 for now */
1256 __ops_crypt_any(&crypt_info
, OPS_SA_AES_256
);
1257 __ops_encrypt_init(&crypt_info
);
1259 encrypted_sz
= (size_t)(len
+ crypt_info
.blocksize
+ 2);
1260 if ((encrypted
= calloc(1, encrypted_sz
)) == NULL
) {
1261 (void) fprintf(stderr
, "can't allocate %" PRIsize
"d\n",
1266 done
= __ops_encrypt_se(&crypt_info
, encrypted
, data
, (unsigned)len
);
1268 (void) fprintf(stderr
,
1269 "__ops_write_symm_enc_data: done != len\n");
1273 return __ops_write_ptag(output
, OPS_PTAG_CT_SE_DATA
) &&
1274 __ops_write_length(output
, 1 + encrypted_sz
) &&
1275 __ops_write(output
, data
, (unsigned)len
);
1279 \ingroup Core_WritePackets
1280 \brief Write a One Pass Signature packet
1281 \param seckey Secret Key to use
1282 \param hash_alg Hash Algorithm to use
1283 \param sig_type Signature type
1284 \param output Write settings
1285 \return 1 if OK; else 0
1288 __ops_write_one_pass_sig(__ops_output_t
*output
,
1289 const __ops_seckey_t
*seckey
,
1290 const __ops_hash_alg_t hash_alg
,
1291 const __ops_sig_type_t sig_type
)
1293 unsigned char keyid
[OPS_KEY_ID_SIZE
];
1295 __ops_keyid(keyid
, OPS_KEY_ID_SIZE
, &seckey
->pubkey
);
1296 return __ops_write_ptag(output
, OPS_PTAG_CT_1_PASS_SIG
) &&
1297 __ops_write_length(output
, 1 + 1 + 1 + 1 + 8 + 1) &&
1298 __ops_write_scalar(output
, 3, 1) /* version */ &&
1299 __ops_write_scalar(output
, (unsigned)sig_type
, 1) &&
1300 __ops_write_scalar(output
, (unsigned)hash_alg
, 1) &&
1301 __ops_write_scalar(output
, (unsigned)seckey
->pubkey
.alg
, 1) &&
1302 __ops_write(output
, keyid
, 8) &&
1303 __ops_write_scalar(output
, 1, 1);