Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F22948305
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
158 KB
Subscribers
None
View Options
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index 72d617a5c..5dbaf7195 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -1,609 +1,621 @@
/* blowfish.c - Blowfish encryption
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 336 ff.
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Test values:
* key "abcdefghijklmnopqrstuvwxyz";
* plain "BLOWFISH"
* cipher 32 4E D0 FE F4 13 A2 03
+ *
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "types.h"
#include "blowfish.h"
/* precomputed S boxes */
static const u32 ks0[256] = {
0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,
0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,
0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658,
0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,
0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,
0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6,
0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,
0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,
0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1,
0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,
0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,
0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176,
0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,
0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,
0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B,
0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,
0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,
0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A,
0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,
0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,
0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8,
0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,
0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,
0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0,
0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,
0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,
0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705,
0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,
0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,
0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9,
0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,
0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,
0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A };
static const u32 ks1[256] = {
0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,
0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,
0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65,
0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,
0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,
0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D,
0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,
0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,
0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908,
0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,
0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,
0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908,
0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,
0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,
0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA,
0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,
0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,
0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5,
0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,
0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,
0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA,
0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,
0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,
0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054,
0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,
0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,
0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646,
0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,
0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,
0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E,
0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,
0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,
0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 };
static const u32 ks2[256] = {
0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,
0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,
0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF,
0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,
0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,
0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC,
0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,
0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,
0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58,
0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,
0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,
0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60,
0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,
0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,
0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74,
0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,
0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,
0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979,
0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,
0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,
0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086,
0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,
0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,
0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84,
0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,
0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,
0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE,
0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,
0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,
0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188,
0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,
0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,
0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 };
static const u32 ks3[256] = {
0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,
0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,
0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79,
0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,
0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,
0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1,
0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,
0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,
0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6,
0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,
0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,
0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5,
0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,
0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,
0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD,
0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,
0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,
0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC,
0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,
0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,
0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A,
0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,
0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,
0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B,
0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,
0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,
0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623,
0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,
0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,
0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3,
0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,
0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,
0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 };
static const u32 ps[BLOWFISH_ROUNDS+2] = {
0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,
0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,
0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B };
static u32
function_F( BLOWFISH_context *bc, u32 x )
{
u16 a, b, c, d;
#ifdef BIG_ENDIAN_HOST
a = ((byte*)&x)[0];
b = ((byte*)&x)[1];
c = ((byte*)&x)[2];
d = ((byte*)&x)[3];
#else
a = ((byte*)&x)[3];
b = ((byte*)&x)[2];
c = ((byte*)&x)[1];
d = ((byte*)&x)[0];
#endif
return ((bc->s0[a] + bc->s1[b]) ^ bc->s2[c] ) + bc->s3[d];
}
static void
encrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
u32 xl, xr, temp;
int i;
xl = *ret_xl;
xr = *ret_xr;
for(i=0; i < BLOWFISH_ROUNDS; i++ ) {
xl ^= bc->p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= bc->p[BLOWFISH_ROUNDS];
xl ^= bc->p[BLOWFISH_ROUNDS+1];
*ret_xl = xl;
*ret_xr = xr;
}
static void
decrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
u32 xl, xr, temp;
int i;
xl = *ret_xl;
xr = *ret_xr;
for(i=BLOWFISH_ROUNDS+1; i > 1; i-- ) {
xl ^= bc->p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= bc->p[1];
xl ^= bc->p[0];
*ret_xl = xl;
*ret_xr = xr;
}
static void
encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
u32 d1, d2;
#ifdef BIG_ENDIAN_HOST
d1 = ((u32*)inbuf)[0]; /* fixme: this may not be aligned */
d2 = ((u32*)inbuf)[1];
#else
((byte*)&d1)[3] = inbuf[0];
((byte*)&d1)[2] = inbuf[1];
((byte*)&d1)[1] = inbuf[2];
((byte*)&d1)[0] = inbuf[3];
((byte*)&d2)[3] = inbuf[4];
((byte*)&d2)[2] = inbuf[5];
((byte*)&d2)[1] = inbuf[6];
((byte*)&d2)[0] = inbuf[7];
#endif
encrypt( bc, &d1, &d2 );
#ifdef BIG_ENDIAN_HOST
((u32*)outbuf)[0] = d1;
((u32*)outbuf)[1] = d2;
#else
outbuf[0] = ((byte*)&d1)[3];
outbuf[1] = ((byte*)&d1)[2];
outbuf[2] = ((byte*)&d1)[1];
outbuf[3] = ((byte*)&d1)[0];
outbuf[4] = ((byte*)&d2)[3];
outbuf[5] = ((byte*)&d2)[2];
outbuf[6] = ((byte*)&d2)[1];
outbuf[7] = ((byte*)&d2)[0];
#endif
}
static void
decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
u32 d1, d2;
#ifdef BIG_ENDIAN_HOST
d1 = ((u32*)inbuf)[0]; /* fixme: this may not be aligned */
d2 = ((u32*)inbuf)[1];
#else
((byte*)&d1)[3] = inbuf[0];
((byte*)&d1)[2] = inbuf[1];
((byte*)&d1)[1] = inbuf[2];
((byte*)&d1)[0] = inbuf[3];
((byte*)&d2)[3] = inbuf[4];
((byte*)&d2)[2] = inbuf[5];
((byte*)&d2)[1] = inbuf[6];
((byte*)&d2)[0] = inbuf[7];
#endif
decrypt( bc, &d1, &d2 );
#ifdef BIG_ENDIAN_HOST
((u32*)outbuf)[0] = d1;
((u32*)outbuf)[1] = d2;
#else
outbuf[0] = ((byte*)&d1)[3];
outbuf[1] = ((byte*)&d1)[2];
outbuf[2] = ((byte*)&d1)[1];
outbuf[3] = ((byte*)&d1)[0];
outbuf[4] = ((byte*)&d2)[3];
outbuf[5] = ((byte*)&d2)[2];
outbuf[6] = ((byte*)&d2)[1];
outbuf[7] = ((byte*)&d2)[0];
#endif
}
static void
selftest()
{
BLOWFISH_context c;
byte plain[] = "BLOWFISH";
byte buffer[8];
+ byte plain3[] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };
+ byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
+ byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
blowfish_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
encrypt_block( &c, buffer, plain );
if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
log_error("wrong blowfish encryption\n");
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
log_bug("blowfish failed\n");
+
+ blowfish_setkey( &c, key3, 8 );
+ encrypt_block( &c, buffer, plain3 );
+ if( memcmp( buffer, cipher3, 8 ) )
+ log_error("wrong blowfish encryption (3)\n");
+ decrypt_block( &c, buffer, buffer );
+ if( memcmp( buffer, plain3, 8 ) )
+ log_bug("blowfish failed (3)\n");
}
void
blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
{
int i, j, k;
u32 data, datal, datar;
static int initialized;
if( !initialized ) {
initialized = 1;
selftest();
}
for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
c->p[i] = ps[i];
for(i=0; i < 256; i++ ) {
c->s0[i] = ks0[i];
c->s1[i] = ks1[i];
c->s2[i] = ks2[i];
c->s3[i] = ks3[i];
}
for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) {
#ifdef BIG_ENDIAN_HOST
((byte*)&data)[0] = key[j];
((byte*)&data)[1] = key[(j+1)%keylen];
((byte*)&data)[2] = key[(j+2)%keylen];
((byte*)&data)[3] = key[(j+3)%keylen];
#else
((byte*)&data)[3] = key[j];
((byte*)&data)[2] = key[(j+1)%keylen];
((byte*)&data)[1] = key[(j+2)%keylen];
((byte*)&data)[0] = key[(j+3)%keylen];
#endif
c->p[i] ^= data;
j = (j+4) % keylen;
}
datal = datar = 0;
for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 ) {
encrypt( c, &datal, &datar );
c->p[i] = datal;
c->p[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s0[i] = datal;
c->s0[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s1[i] = datal;
c->s1[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s2[i] = datal;
c->s2[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s3[i] = datal;
c->s3[i+1] = datar;
}
}
void
blowfish_setiv( BLOWFISH_context *c, byte *iv )
{
if( iv )
memcpy( c->iv, iv, BLOWFISH_BLOCKSIZE );
else
memset( c->iv, 0, BLOWFISH_BLOCKSIZE );
c->count = 0;
encrypt_block( c, c->eniv, c->iv );
}
void
blowfish_encode( BLOWFISH_context *c, byte *outbuf, byte *inbuf,
unsigned nblocks )
{
unsigned n;
for(n=0; n < nblocks; n++ ) {
encrypt_block( c, outbuf, inbuf );
inbuf += BLOWFISH_BLOCKSIZE;;
outbuf += BLOWFISH_BLOCKSIZE;
}
}
void
blowfish_decode( BLOWFISH_context *c, byte *outbuf, byte *inbuf,
unsigned nblocks )
{
unsigned n;
for(n=0; n < nblocks; n++ ) {
decrypt_block( c, outbuf, inbuf );
inbuf += BLOWFISH_BLOCKSIZE;;
outbuf += BLOWFISH_BLOCKSIZE;
}
}
/****************
* FIXME: Make use of bigger chunks
* (out may overlap with a or b)
*/
static void
xorblock( byte *out, byte *a, byte *b, unsigned count )
{
for( ; count ; count--, a++, b++ )
*out++ = *a ^ *b ;
}
/****************
* Encode buffer in CFB mode. nbytes can be an arbitrary value.
*/
void
blowfish_encode_cfb( BLOWFISH_context *c, byte *outbuf,
byte *inbuf, unsigned nbytes)
{
unsigned n;
if( c->count ) { /* must make a full block first */
assert( c->count < BLOWFISH_BLOCKSIZE );
n = BLOWFISH_BLOCKSIZE - c->count;
if( n > nbytes )
n = nbytes;
xorblock( outbuf, c->eniv+c->count, inbuf, n);
memcpy( c->iv+c->count, outbuf, n);
c->count += n;
nbytes -= n;
inbuf += n;
outbuf += n;
assert( c->count <= BLOWFISH_BLOCKSIZE);
if( c->count == BLOWFISH_BLOCKSIZE ) {
encrypt_block( c, c->eniv, c->iv );
c->count = 0;
}
else
return;
}
assert(!c->count);
while( nbytes >= BLOWFISH_BLOCKSIZE ) {
xorblock( outbuf, c->eniv, inbuf, BLOWFISH_BLOCKSIZE);
memcpy( c->iv, outbuf, BLOWFISH_BLOCKSIZE);
encrypt_block( c, c->eniv, c->iv );
nbytes -= BLOWFISH_BLOCKSIZE;
inbuf += BLOWFISH_BLOCKSIZE;
outbuf += BLOWFISH_BLOCKSIZE;
}
if( nbytes ) {
xorblock( outbuf, c->eniv, inbuf, nbytes );
memcpy( c->iv, outbuf, nbytes );
c->count = nbytes;
}
}
void
blowfish_decode_cfb( BLOWFISH_context *c, byte *outbuf,
byte *inbuf, unsigned nbytes)
{
unsigned n;
if( c->count ) { /* must make a full block first */
assert( c->count < BLOWFISH_BLOCKSIZE );
n = BLOWFISH_BLOCKSIZE - c->count;
if( n > nbytes )
n = nbytes;
memcpy( c->iv+c->count, inbuf, n);
xorblock( outbuf, c->eniv+c->count, inbuf, n);
c->count += n;
nbytes -= n;
inbuf += n;
outbuf += n;
assert( c->count <= BLOWFISH_BLOCKSIZE);
if( c->count == BLOWFISH_BLOCKSIZE ) {
encrypt_block( c, c->eniv, c->iv );
c->count = 0;
}
else
return;
}
assert(!c->count);
while( nbytes >= BLOWFISH_BLOCKSIZE ) {
memcpy( c->iv, inbuf, BLOWFISH_BLOCKSIZE);
xorblock( outbuf, c->eniv, inbuf, BLOWFISH_BLOCKSIZE);
encrypt_block( c, c->eniv, c->iv );
nbytes -= BLOWFISH_BLOCKSIZE;
inbuf += BLOWFISH_BLOCKSIZE;
outbuf += BLOWFISH_BLOCKSIZE;
}
if( nbytes ) {
memcpy( c->iv, inbuf, nbytes );
xorblock( outbuf, c->eniv, inbuf, nbytes );
c->count = nbytes;
}
}
diff --git a/doc/DETAILS b/doc/DETAILS
index a3a2773fb..81aff2912 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -1,108 +1,109 @@
* For packet version 3 we calculate the keyids this way:
RSA := low 64 bits of n
ELGAMAL := build a v3 pubkey packet (with CTB 0x99) and calculate
a rmd160 hash value from it. This is used as the
fingerprint and the low 64 bits are the keyid.
Layout of the TrustDB
=====================
The TrustDB is build from fixed length records, where the first bytes
describes the record type. All numeric values are stored in network
byte order. The length of each record is 40 bytes. The first record of
the DB is always of type 1 and this is the only record of this type.
Record type 0:
--------------
Unused record, can be reused for any purpose.
Record type 1:
--------------
Version information for this TrustDB. This is always the first
record of the DB and the onyl one with type 1.
1 byte value 1
3 bytes 'g10' magic value
1 byte Version of the TrustDB
3 byte reserved
1 u32 locked by (pid) 0 = not locked.
1 u32 timestamp of trustdb creation
1 u32 timestamp of last modification
1 u32 timestamp of last validation
(Used to keep track of the time, when this TrustDB was checked
against the pubring)
1 u32 Local-Id-Counter. Used to keep track of Local-IDs.
32 bits are enough numbers for all practial purposes; if this
- counter rolls over (due to deleted keyblock,an d new ones),
+ counter rolls over (due to deleted keyblock and new ones),
the software should reassign new Local-Ids to the whole
database (not expected to ever occur).
1 byte marginals needed
1 byte completes needed
1 byte max. cert depth
If any of this 3 values are changed, all cache records
muts be invalidated.
9 bytes reserved
Record type 2:
--------------
Informations about a public key certificate.
+ These are static values which are never changed without user interaction.
1 byte value 2
1 byte reserved
1 u32 Local-Id. This is used to bind all records for
a given certificate together. It is valid only in this TrustDB
and usefull if we have duplicate keyids
It is not defined, how an implementaion selects such
a Local-Id, but it may use the local-ID counter from
- record type 1
+ record type 1, or simply use the offset of Record type 2
8 bytes keyid (of the primary key)
1 byte pubkey algorithm
1 byte reserved
20 bytes fingerprint of the public key
1 byte ownertrust:
Bits 2-0:
0 = undefined (not yet initialized)
1 = unknown owner (could not initialize it)
2 = do not trust this owner
- 3 = usually trust this owner
- 4 = always trust this owner
- 5 = ultimately trust this owner. This can only be set if
+ 4 = usually trust this owner
+ 5 = always trust this owner
+ 7 = ultimately trust this owner. This can only be set if
we have control over the secret key too.
Bit 3: set if key is revoked; do not use it.
Bit 7-4: reserved
3 byte reserved
Record type 3: (cache record)
--------------
Used to bind the trustDB to the concrete instance of keyblock in
a pubring. This is used to cache informations.
1 byte value 3
1 byte reserved
1 u32 Local-Id.
8 bytes keyid of the primary key
1 byte cache-is-valid the following stuff is only
valid if this is set.
1 byte reserved
20 bytes rmd160 hash value over the complete keyblock
This is used to detect any changes of the keyblock with all
CTBs and lengths headers. Calculation is easy if the keyblock
is optained from a keyserved: simply create the hash from all
received data bytes.
1 byte number of untrusted signatures.
1 byte number of marginal trusted signatures.
1 byte number of fully trusted signatures.
(255 is stored for all values greater than 254)
1 byte Trustlevel
0 = undefined (not calculated)
1 = unknown
2 = not trusted
3 = marginally trusted
4 = fully trusted
5 = ultimately trusted (have secret key too).
diff --git a/g10/encode.c b/g10/encode.c
index 688cbfc08..ff125079e 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -1,333 +1,334 @@
/* encode.c - encode data
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "filter.h"
static int encode_simple( const char *filename, int mode );
static int write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out );
/****************
* Encode FILENAME only with the symmetric cipher. Take input from
* stdin if FILENAME is NULL.
*/
int
encode_symmetric( const char *filename )
{
return encode_simple( filename, 1 );
}
/****************
* Encode FILENAME as literal data packet only. Take input from
* stdin if FILENAME is NULL.
*/
int
encode_store( const char *filename )
{
return encode_simple( filename, 0 );
}
static int
encode_simple( const char *filename, int mode )
{
IOBUF inp, out;
PACKET pkt;
PKT_plaintext *pt;
int rc = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
/* prepare iobufs */
if( !(inp = iobuf_open(filename)) ) {
log_error("can't open %s: %s\n", filename? filename: "[stdin]",
strerror(errno) );
return G10ERR_OPEN_FILE;
}
cfx.dek = NULL;
if( mode ) {
cfx.dek = m_alloc_secure( sizeof *cfx.dek );
cfx.dek->algo = opt.def_cipher_algo;
if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
m_free(cfx.dek);
iobuf_close(inp);
log_error("error creating passphrase: %s\n", g10_errstr(rc) );
return rc;
}
}
if( !(out = open_outfile( filename, opt.armor? 1:0 )) ) {
iobuf_close(inp);
m_free(cfx.dek);
return G10ERR_CREATE_FILE; /* or user said: do not overwrite */
}
if( opt.armor )
iobuf_push_filter( out, armor_filter, &afx );
write_comment( out, "#Created by G10 pre-release " VERSION );
if( opt.compress )
iobuf_push_filter( out, compress_filter, &zfx );
/* setup the inner packet */
if( filename ) {
pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
pt->namelen = strlen(filename);
memcpy(pt->name, filename, pt->namelen );
if( !(filesize = iobuf_get_filelength(inp)) )
log_info("warning: '%s' is an empty file\n", filename );
}
else { /* no filename */
pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
filesize = 0; /* stdin */
}
pt->timestamp = make_timestamp();
pt->mode = 'b';
pt->len = filesize;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
/* register the cipher filter */
if( mode )
iobuf_push_filter( out, cipher_filter, &cfx );
/* do the work */
if( (rc = build_packet( out, &pkt )) )
log_error("build_packet failed: %s\n", g10_errstr(rc) );
/* finish the stuff */
iobuf_close(inp);
iobuf_close(out); /* fixme: check returncode */
pt->buf = NULL;
free_packet(&pkt);
m_free(cfx.dek);
return rc;
}
/****************
* Encrypt the file with the given userids (or ask if none
* is supplied).
*/
int
encode_crypt( const char *filename, STRLIST remusr )
{
IOBUF inp = NULL, out = NULL;
PACKET pkt;
- PKT_plaintext *pt;
+ PKT_plaintext *pt = NULL;
int rc = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
PKC_LIST pkc_list;
memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
if( (rc=build_pkc_list( remusr, &pkc_list)) )
return rc;
/* prepare iobufs */
if( !(inp = iobuf_open(filename)) ) {
log_error("can't open %s: %s\n", filename? filename: "[stdin]",
strerror(errno) );
rc = G10ERR_OPEN_FILE;
goto leave;
}
else if( opt.verbose )
log_error("reading from '%s'\n", filename? filename: "[stdin]");
if( !(out = open_outfile( filename, opt.armor? 1:0 )) ) {
rc = G10ERR_CREATE_FILE; /* or user said: do not overwrite */
goto leave;
}
if( opt.armor )
iobuf_push_filter( out, armor_filter, &afx );
write_comment( out, "#Created by G10 pre-release " VERSION );
if( opt.compress )
iobuf_push_filter( out, compress_filter, &zfx );
/* create a session key */
cfx.dek = m_alloc_secure( sizeof *cfx.dek );
cfx.dek->algo = opt.def_cipher_algo;
make_session_key( cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
rc = write_pubkey_enc_from_list( pkc_list, cfx.dek, out );
if( rc )
goto leave;
/* setup the inner packet */
if( filename ) {
pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
pt->namelen = strlen(filename);
memcpy(pt->name, filename, pt->namelen );
if( !(filesize = iobuf_get_filelength(inp)) )
log_info("warning: '%s' is an empty file\n", filename );
}
else { /* no filename */
pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
filesize = 0; /* stdin */
}
pt->timestamp = make_timestamp();
pt->mode = 'b';
pt->len = filesize;
pt->buf = inp;
init_packet(&pkt);
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
/* register the cipher filter */
iobuf_push_filter( out, cipher_filter, &cfx );
/* do the work */
if( (rc = build_packet( out, &pkt )) )
log_error("build_packet failed: %s\n", g10_errstr(rc) );
/* finish the stuff */
leave:
iobuf_close(inp);
if( rc )
iobuf_cancel(out);
else
iobuf_close(out); /* fixme: check returncode */
- pt->buf = NULL;
+ if( pt )
+ pt->buf = NULL;
free_packet(&pkt);
m_free(cfx.dek);
release_pkc_list( pkc_list );
return rc;
}
/****************
* Filter to do a complete public key encryption.
*/
int
encrypt_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
encrypt_filter_context_t *efx = opaque;
int rc=0;
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
log_bug(NULL); /* not used */
}
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
if( !efx->header_okay ) {
efx->cfx.dek = m_alloc_secure( sizeof *efx->cfx.dek );
efx->cfx.dek->algo = opt.def_cipher_algo;
make_session_key( efx->cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ",
efx->cfx.dek->key, efx->cfx.dek->keylen );
rc = write_pubkey_enc_from_list( efx->pkc_list, efx->cfx.dek, a );
if( rc )
return rc;
iobuf_push_filter( a, cipher_filter, &efx->cfx );
efx->header_okay = 1;
}
rc = iobuf_write( a, buf, size );
}
else if( control == IOBUFCTRL_FREE ) {
}
else if( control == IOBUFCTRL_DESC ) {
*(char**)buf = "encrypt_filter";
}
return rc;
}
/****************
* Write pubkey-enc packets from the list of PKCs to OUT.
*/
static int
write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out )
{
PACKET pkt;
PKT_public_cert *pkc;
PKT_pubkey_enc *enc;
int rc;
for( ; pkc_list; pkc_list = pkc_list->next ) {
pkc = pkc_list->pkc;
enc = m_alloc_clear( sizeof *enc );
enc->pubkey_algo = pkc->pubkey_algo;
if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
g10_elg_encrypt( pkc, enc, dek );
else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
g10_rsa_encrypt( pkc, enc, dek );
else
log_bug(NULL);
/* and write it */
init_packet(&pkt);
pkt.pkttype = PKT_PUBKEY_ENC;
pkt.pkt.pubkey_enc = enc;
rc = build_packet( out, &pkt );
free_pubkey_enc(enc);
if( rc ) {
log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
return rc;
}
}
return 0;
}
diff --git a/g10/free-packet.c b/g10/free-packet.c
index fb5949a8f..e2efa5a66 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -1,243 +1,285 @@
/* free-packet.c - cleanup stuff for packets
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "packet.h"
#include "iobuf.h"
#include "mpi.h"
#include "util.h"
#include "cipher.h"
#include "memory.h"
void
free_pubkey_enc( PKT_pubkey_enc *enc )
{
if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
mpi_free( enc->d.elg.a );
mpi_free( enc->d.elg.b );
}
else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
mpi_free( enc->d.rsa.rsa_integer );
m_free(enc);
}
void
free_seckey_enc( PKT_signature *enc )
{
if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
mpi_free( enc->d.elg.a );
mpi_free( enc->d.elg.b );
}
else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
mpi_free( enc->d.rsa.rsa_integer );
m_free(enc);
}
void
-free_public_cert( PKT_public_cert *cert )
+release_public_cert_parts( PKT_public_cert *cert )
{
if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
- mpi_free( cert->d.elg.p );
- mpi_free( cert->d.elg.g );
- mpi_free( cert->d.elg.y );
+ mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL;
+ mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
+ mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
}
else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
- mpi_free( cert->d.rsa.rsa_n );
- mpi_free( cert->d.rsa.rsa_e );
+ mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL;
+ mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL;
}
- md_close( cert->mfx.md );
+ md_close( cert->mfx.md ); cert->mfx.md = NULL;
+}
+
+void
+free_public_cert( PKT_public_cert *cert )
+{
+ release_public_cert_parts( cert );
m_free(cert);
}
PKT_public_cert *
copy_public_cert( PKT_public_cert *d, PKT_public_cert *s )
{
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
if( s->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
d->d.elg.p = mpi_copy( s->d.elg.p );
d->d.elg.g = mpi_copy( s->d.elg.g );
d->d.elg.y = mpi_copy( s->d.elg.y );
}
else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) {
d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n );
d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e );
}
d->mfx.md = NULL;
return d;
}
void
-free_secret_cert( PKT_secret_cert *cert )
+release_secret_cert_parts( PKT_secret_cert *cert )
{
if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
- mpi_free( cert->d.elg.p );
- mpi_free( cert->d.elg.g );
- mpi_free( cert->d.elg.y );
- mpi_free( cert->d.elg.x );
+ mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL;
+ mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
+ mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
+ mpi_free( cert->d.elg.x ); cert->d.elg.x = NULL;
}
else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
- mpi_free( cert->d.rsa.rsa_n );
- mpi_free( cert->d.rsa.rsa_e );
- mpi_free( cert->d.rsa.rsa_d );
- mpi_free( cert->d.rsa.rsa_p );
- mpi_free( cert->d.rsa.rsa_q );
- mpi_free( cert->d.rsa.rsa_u );
+ mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL;
+ mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL;
+ mpi_free( cert->d.rsa.rsa_d ); cert->d.rsa.rsa_d = NULL;
+ mpi_free( cert->d.rsa.rsa_p ); cert->d.rsa.rsa_p = NULL;
+ mpi_free( cert->d.rsa.rsa_q ); cert->d.rsa.rsa_q = NULL;
+ mpi_free( cert->d.rsa.rsa_u ); cert->d.rsa.rsa_u = NULL;
}
+}
+
+void
+free_secret_cert( PKT_secret_cert *cert )
+{
+ release_secret_cert_parts( cert );
m_free(cert);
}
PKT_secret_cert *
copy_secret_cert( PKT_secret_cert *d, PKT_secret_cert *s )
{
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
if( s->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
d->d.elg.p = mpi_copy( s->d.elg.p );
d->d.elg.g = mpi_copy( s->d.elg.g );
d->d.elg.y = mpi_copy( s->d.elg.y );
d->d.elg.x = mpi_copy( s->d.elg.x );
}
else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) {
d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n );
d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e );
d->d.rsa.rsa_d = mpi_copy( s->d.rsa.rsa_d );
d->d.rsa.rsa_p = mpi_copy( s->d.rsa.rsa_p );
d->d.rsa.rsa_q = mpi_copy( s->d.rsa.rsa_q );
d->d.rsa.rsa_u = mpi_copy( s->d.rsa.rsa_u );
}
return d;
}
void
free_comment( PKT_comment *rem )
{
m_free(rem);
}
void
free_user_id( PKT_user_id *uid )
{
m_free(uid);
}
void
free_compressed( PKT_compressed *zd )
{
if( zd->buf ) { /* have to skip some bytes */
/* don't have any informations about the length, so
* we assume this is the last packet */
while( iobuf_get(zd->buf) != -1 )
;
}
m_free(zd);
}
void
free_encrypted( PKT_encrypted *ed )
{
if( ed->buf ) { /* have to skip some bytes */
if( iobuf_in_block_mode(ed->buf) ) {
while( iobuf_get(ed->buf) != -1 )
;
iobuf_set_block_mode(ed->buf, 0);
}
else {
for( ; ed->len; ed->len-- ) /* skip the packet */
iobuf_get(ed->buf);
}
}
m_free(ed);
}
void
free_plaintext( PKT_plaintext *pt )
{
if( pt->buf ) { /* have to skip some bytes */
if( iobuf_in_block_mode(pt->buf) ) {
while( iobuf_get(pt->buf) != -1 )
;
iobuf_set_block_mode(pt->buf, 0);
}
else {
for( ; pt->len; pt->len-- ) /* skip the packet */
iobuf_get(pt->buf);
}
}
m_free(pt);
}
/****************
* Free the packet in pkt.
*/
void
free_packet( PACKET *pkt )
{
if( !pkt || !pkt->pkt.generic )
return;
if( DBG_MEMORY )
log_debug("free_packet() type=%d\n", pkt->pkttype );
switch( pkt->pkttype ) {
case PKT_SIGNATURE:
free_seckey_enc( pkt->pkt.signature );
break;
case PKT_PUBKEY_ENC:
free_pubkey_enc( pkt->pkt.pubkey_enc );
break;
case PKT_PUBLIC_CERT:
free_public_cert( pkt->pkt.public_cert );
break;
case PKT_SECRET_CERT:
free_secret_cert( pkt->pkt.secret_cert );
break;
case PKT_COMMENT:
free_comment( pkt->pkt.comment );
break;
case PKT_USER_ID:
free_user_id( pkt->pkt.user_id );
break;
case PKT_COMPRESSED:
free_compressed( pkt->pkt.compressed);
break;
case PKT_ENCRYPTED:
free_encrypted( pkt->pkt.encrypted );
break;
case PKT_PLAINTEXT:
free_plaintext( pkt->pkt.plaintext );
break;
default:
m_free( pkt->pkt.generic );
break;
}
pkt->pkt.generic = NULL;
}
+/****************
+ * Returns 0 if they match.
+ */
+int
+cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc )
+{
+ if( pkc->timestamp != skc->timestamp )
+ return -1;
+ if( pkc->valid_days != skc->valid_days )
+ return -1;
+ if( pkc->pubkey_algo != skc->pubkey_algo )
+ return -1;
+
+ if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
+ if( mpi_cmp( pkc->d.elg.p , skc->d.elg.p ) )
+ return -1;
+ if( mpi_cmp( pkc->d.elg.g , skc->d.elg.g ) )
+ return -1;
+ if( mpi_cmp( pkc->d.elg.y , skc->d.elg.y ) )
+ return -1;
+ }
+ else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ if( mpi_cmp( pkc->d.rsa.rsa_n , skc->d.rsa.rsa_n ) )
+ return -1;
+ if( mpi_cmp( pkc->d.rsa.rsa_e , skc->d.rsa.rsa_e ) )
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/g10/g10.c b/g10/g10.c
index e5c7139d1..2002e69e1 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -1,659 +1,678 @@
/* g10.c - The G10 utility
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "packet.h"
#include "iobuf.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "options.h"
#include "keydb.h"
#include "mpi.h"
#include "cipher.h"
#include "filter.h"
#include "trustdb.h"
enum cmd_values { aNull = 0,
aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr,
aPrintMDs, aSignKey, aClearsig, aListPackets, aEditSig,
aKMode, aKModeC, aChangePass,
aTest };
static void set_cmd( enum cmd_values *ret_cmd,
enum cmd_values new_cmd );
static void print_hex( byte *p, size_t n );
static void print_mds( const char *fname );
static void do_test(int);
const char *
strusage( int level )
{
const char *p;
switch( level ) {
case 10:
case 0: p = "g10 - v" VERSION "; "
"Copyright 1997 Werner Koch (dd9jn)\n" ; break;
case 13: p = "g10"; break;
case 14: p = VERSION; break;
case 1:
case 11: p = "Usage: g10 [options] [files] (-h for help)";
break;
case 2:
case 12: p =
"Syntax: g10 [options] [files]\n"
"sign, check, encrypt or decrypt\n"
"default operation depends on the input data\n"; break;
case 26:
p = "Please report bugs to <g10-bugs@isil.d.shuttle.de>.\n";
break;
case 30: p = ""
#ifndef HAVE_ZLIB_H
" NOTE: This version is compiled without ZLIB support;\n"
" you are not able to process compresssed data!\n"
#endif
#ifdef HAVE_RSA_CIPHER
"WARNING: This version has RSA support! Your are not allowed to\n"
" use it inside the Unites States before Sep 30, 2000!\n"
#endif
;
break;
default: p = default_strusage(level);
}
return p;
}
static void
set_debug(void)
{
if( opt.debug & DBG_MEMORY_VALUE )
memory_debug_mode = 1;
if( opt.debug & DBG_MEMSTAT_VALUE )
memory_stat_debug_mode = 1;
if( opt.debug & DBG_MPI_VALUE )
mpi_debug_mode = 1;
if( opt.debug & DBG_CIPHER_VALUE )
cipher_debug_mode = 1;
if( opt.debug & DBG_IOBUF_VALUE )
iobuf_debug_mode = 1;
}
static void
set_cmd( enum cmd_values *ret_cmd, enum cmd_values new_cmd )
{
enum cmd_values cmd = *ret_cmd;
if( !cmd || cmd == new_cmd )
cmd = new_cmd;
else if( cmd == aSign && new_cmd == aEncr )
cmd = aSignEncr;
else if( cmd == aEncr && new_cmd == aSign )
cmd = aSignEncr;
else if( cmd == aKMode && new_cmd == aSym )
cmd = aKModeC;
else {
log_error("conflicting commands\n");
exit(2);
}
*ret_cmd = cmd;
}
int
main( int argc, char **argv )
{
static ARGPARSE_OPTS opts[] = {
{ 'a', "armor", 0, "create ascii armored output"},
{ 'v', "verbose", 0, "verbose" },
{ 'z', NULL, 1, "set compress level (0 disables)" },
{ 'n', "dry-run", 0, "don't make any changes" },
{ 'c', "symmetric", 0, "do only a symmetric encryption" },
{ 'o', "output", 2, "use as output file" },
{ 500, "batch", 0, "batch mode: never ask" },
{ 501, "yes", 0, "assume yes on most questions"},
{ 502, "no", 0, "assume no on most questions"},
{ 503, "gen-key", 0, "generate a new key pair" },
{ 504, "add-key", 0, "add key to the public keyring" },
{ 505, "delete-key",0, "remove key from public keyring" },
{ 506, "sign-key" ,0, "make a signature on a key in the keyring" },
{ 507, "store", 0, "store only" },
{ 508, "check-key" ,0, "check signatures on a key in the keyring" },
{ 509, "keyring" ,2, "add this keyring to the list of keyrings" },
{ 's', "sign", 0, "make a signature"},
{ 't', "textmode", 0, "use canonical text mode"},
{ 'b', "detach-sign", 0, "make a detached signature"},
{ 'e', "encrypt", 0, "encrypt data" },
{ 'd', "decrypt", 0, "decrypt data (default)" },
{ 'u', "local-user",2, "use this user-id to sign or decrypt" },
{ 'r', "remote-user", 2, "use this user-id for encryption" },
{ 'k', NULL , 0, "list keys" },
{ 510, "debug" ,4|16, "set debugging flags" },
{ 511, "debug-all" ,0, "enable full debugging"},
{ 512, "cache-all" ,0, "hold everything in memory"},
{ 513, "gen-prime" , 0, "\r" },
{ 514, "test" , 0, "\r" },
{ 515, "fingerprint", 0, "show the fingerprints"},
{ 516, "print-mds" , 0, "print all message digests"},
{ 517, "secret-keyring" ,2, "add this secret keyring to the list" },
{ 518, "options" , 2, "read options from file" },
{ 519, "no-armor", 0, "\r"},
{ 520, "no-default-keyring", 0, "\r" },
{ 521, "list-packets",0,"list only the sequence of packets"},
{ 522, "no-greeting", 0, "\r" },
{ 523, "passphrase-fd",1, "\r" },
{ 524, "edit-sig" ,0, "edit a key signature" },
{ 525, "change-passphrase", 0, "change the passphrase of your secret keyring"},
{ 526, "no-verbose", 0, "\r"},
{ 527, "cipher-algo", 2 , "select default cipher algorithm" },
{ 528, "pubkey-algo", 2 , "select default puplic key algorithm" },
{ 529, "digest-algo", 2 , "select default message digest algorithm" },
{0} };
ARGPARSE_ARGS pargs;
IOBUF a;
int rc;
int orig_argc;
char **orig_argv;
const char *fname, *fname_print;
STRLIST sl, remusr= NULL, locusr=NULL;
int nrings=0, sec_nrings=0;
armor_filter_context_t afx;
const char *s;
int detached_sig = 0;
FILE *configfp = NULL;
char *configname = NULL;
unsigned configlineno;
int parse_verbose = 0;
int default_config =1;
int errors=0;
int default_keyring = 1;
int greeting = 1;
enum cmd_values cmd = 0;
opt.compress = -1; /* defaults to standard compress level */
opt.def_cipher_algo = CIPHER_ALGO_BLOWFISH;
opt.def_pubkey_algo = PUBKEY_ALGO_ELGAMAL;
opt.def_digest_algo = DIGEST_ALGO_RMD160;
/* check wether we have a config file on the commandline */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
while( arg_parse( &pargs, opts) ) {
if( pargs.r_opt == 'v' )
parse_verbose++;
else if( pargs.r_opt == 518 ) {
/* yes there is one, so we do not try the default one, but
* read the option file when it is encountered at the commandline
*/
default_config = 0;
}
}
if( default_config )
configname = make_filename("~/.g10", "options", NULL );
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
next_pass:
if( configname ) {
configlineno = 0;
configfp = fopen( configname, "r" );
if( !configfp ) {
if( default_config ) {
if( parse_verbose > 1 )
log_info("note: no default option file '%s'\n", configname );
}
else
log_fatal("option file '%s': %s\n",
configname, strerror(errno) );
m_free(configname); configname = NULL;
}
if( parse_verbose > 1 )
log_info("reading options from '%s'\n", configname );
default_config = 0;
}
while( optfile_parse( configfp, configname, &configlineno,
&pargs, opts) ) {
switch( pargs.r_opt ) {
case 'v': opt.verbose++;
opt.list_sigs=1;
break;
case 'z': opt.compress = pargs.r.ret_int; break;
case 'a': opt.armor = 1; opt.no_armor=0; break;
case 'c': set_cmd( &cmd , aSym); break;
case 'o': opt.outfile = pargs.r.ret_str; break;
case 'e': set_cmd( &cmd, aEncr); break;
case 'b': detached_sig = 1;
/* fall trough */
case 's': set_cmd( &cmd, aSign ); break;
case 't': set_cmd( &cmd , aClearsig); break;
case 'u': /* store the local users */
sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
strcpy(sl->d, pargs.r.ret_str);
sl->next = locusr;
locusr = sl;
break;
case 'r': /* store the remote users */
sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
strcpy(sl->d, pargs.r.ret_str);
sl->next = remusr;
remusr = sl;
break;
case 'k': set_cmd( &cmd, aKMode ); break;
case 500: opt.batch = 1; greeting = 0; break;
case 501: opt.answer_yes = 1; break;
case 502: opt.answer_no = 1; break;
case 503: set_cmd( &cmd, aKeygen); break;
case 506: set_cmd( &cmd, aSignKey); break;
case 507: set_cmd( &cmd, aStore); break;
case 508: opt.check_sigs = 1; opt.list_sigs = 1; break;
case 509: add_keyring(pargs.r.ret_str); nrings++; break;
case 510: opt.debug |= pargs.r.ret_ulong; break;
case 511: opt.debug = ~0; break;
case 512: opt.cache_all = 1; break;
case 513: set_cmd( &cmd, aPrimegen); break;
case 514: set_cmd( &cmd, aTest); break;
case 515: opt.fingerprint = 1; break;
case 516: set_cmd( &cmd, aPrintMDs); break;
case 517: add_secret_keyring(pargs.r.ret_str); sec_nrings++; break;
case 518:
/* config files may not be nested (silently ignore them) */
if( !configfp ) {
m_free(configname);
configname = m_strdup(pargs.r.ret_str);
goto next_pass;
}
break;
case 519: opt.no_armor=1; opt.armor=0; break;
case 520: default_keyring = 0; break;
case 521: set_cmd( &cmd, aListPackets); break;
case 522: greeting = 0; break;
case 523: set_passphrase_fd( pargs.r.ret_int ); break;
case 524: set_cmd( &cmd, aEditSig); break;
case 525: set_cmd( &cmd, aChangePass); break;
case 526: opt.verbose = 0; opt.list_sigs=0; break;
case 527:
opt.def_cipher_algo = string_to_cipher_algo(pargs.r.ret_str);
break;
case 528:
opt.def_pubkey_algo = string_to_pubkey_algo(pargs.r.ret_str);
break;
case 529:
opt.def_digest_algo = string_to_digest_algo(pargs.r.ret_str);
break;
break;
default : errors++; pargs.err = configfp? 1:2; break;
}
}
if( configfp ) {
fclose( configfp );
configfp = NULL;
m_free(configname); configname = NULL;
goto next_pass;
}
m_free( configname ); configname = NULL;
if( !opt.def_cipher_algo || check_cipher_algo(opt.def_cipher_algo) ) {
log_error("selected cipher algorithm is invalid\n");
errors++;
}
if( !opt.def_pubkey_algo || check_pubkey_algo(opt.def_pubkey_algo) ) {
log_error("selected pubkey algorithm is invalid\n");
errors++;
}
if( !opt.def_digest_algo || check_digest_algo(opt.def_digest_algo) ) {
log_error("selected digest algorithm is invalid\n");
errors++;
}
if( errors )
exit(2);
set_debug();
if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */
if( cmd == aKModeC ) {
opt.fingerprint = 1;
cmd = aKMode;
}
opt.list_sigs = 0;
if( opt.verbose > 2 )
opt.check_sigs++;
if( opt.verbose > 1 )
opt.list_sigs++;
opt.verbose = opt.verbose > 1;
}
if( opt.verbose > 1 )
set_packet_list_mode(1);
if( greeting ) {
if( *(s=strusage(10)) )
tty_printf("%s", s);
if( *(s=strusage(30)) )
tty_printf("%s", s);
}
if( !sec_nrings || default_keyring ) { /* add default secret rings */
char *p = make_filename("~/.g10", "secring.g10", NULL );
add_secret_keyring(p);
m_free(p);
}
if( !nrings || default_keyring ) { /* add default ring */
char *p = make_filename("~/.g10", "pubring.g10", NULL );
add_keyring(p);
m_free(p);
}
if( argc ) {
fname_print = fname = *argv;
}
else {
fname_print = "[stdin]";
fname = NULL;
if( get_passphrase_fd() == 0 ) {
/* reading data and passphrase form stdin:
* we assume the first line is the passphrase, so
* we read it now
*/
/* FIXME: doit */
}
}
if( cmd != aPrimegen && cmd != aPrintMDs ) {
rc = check_trustdb(0);
if( rc )
log_error("failed to initialize the TrustDB: %s\n", g10_errstr(rc));
}
switch( cmd ) {
case aStore: /* only store the file */
if( argc > 1 )
usage(1);
if( (rc = encode_store(fname)) )
log_error("encode_store('%s'): %s\n",
fname_print, g10_errstr(rc) );
break;
case aSym: /* encrypt the given file only with the symmetric cipher */
if( argc > 1 )
usage(1);
if( (rc = encode_symmetric(fname)) )
log_error("encode_symmetric('%s'): %s\n", fname_print, g10_errstr(rc) );
break;
case aEncr: /* encrypt the given file */
if( argc > 1 )
usage(1);
if( (rc = encode_crypt(fname,remusr)) )
log_error("encode_crypt('%s'): %s\n", fname_print, g10_errstr(rc) );
break;
case aSign: /* sign the given file */
- if( argc > 1 )
- usage(1);
- if( (rc = sign_file(fname, detached_sig, locusr, 0, NULL)) )
- log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
+ sl = NULL;
+ if( detached_sig ) { /* sign all files */
+ for( ; argc; argc--, argv++ )
+ add_to_strlist( &sl, *argv );
+ }
+ else {
+ if( argc > 1 )
+ usage(1);
+ if( argc ) {
+ sl = m_alloc_clear( sizeof *sl + strlen(fname));
+ strcpy(sl->d, fname);
+ }
+ }
+ if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) )
+ log_error("sign_file: %s\n", g10_errstr(rc) );
+ free_strlist(sl);
break;
case aSignEncr: /* sign and encrypt the given file */
if( argc > 1 )
usage(1);
- if( (rc = sign_file(fname, detached_sig, locusr, 1, remusr)) )
+ if( argc ) {
+ sl = m_alloc_clear( sizeof *sl + strlen(fname));
+ strcpy(sl->d, fname);
+ }
+ else
+ sl = NULL;
+ if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
+ free_strlist(sl);
break;
case aSignKey: /* sign the key given as argument */
if( argc != 1 )
usage(1);
/* note: fname is the user id! */
if( (rc = sign_key(fname, locusr)) )
log_error("sign_key('%s'): %s\n", fname_print, g10_errstr(rc) );
break;
case aEditSig: /* Edit a key signature */
if( argc != 1 )
usage(1);
/* note: fname is the user id! */
if( (rc = edit_keysigs(fname)) )
log_error("edit_keysig('%s'): %s\n", fname_print, g10_errstr(rc) );
break;
case aChangePass: /* Chnage the passphrase */
if( argc > 1 ) /* no arg: use default, 1 arg use this one */
usage(1);
/* note: fname is the user id! */
if( (rc = change_passphrase(fname)) )
log_error("change_passphrase('%s'): %s\n", fname_print,
g10_errstr(rc) );
break;
case aKMode: /* list keyring */
if( !argc ) { /* list the default public keyrings */
int i, seq=0;
const char *s;
while( s=get_keyring(seq++) ) {
if( !(a = iobuf_open(s)) ) {
log_error("can't open '%s'\n", s);
continue;
}
if( seq > 1 )
putchar('\n');
printf("%s\n", s );
for(i=strlen(s); i; i-- )
putchar('-');
putchar('\n');
proc_packets( a );
iobuf_close(a);
}
}
else if( argc == 1) { /* list the given keyring */
if( !(a = iobuf_open(fname)) )
log_fatal("can't open '%s'\n", fname_print);
proc_packets( a );
iobuf_close(a);
}
else
usage(1);
break;
case aPrimegen:
if( argc == 1 ) {
mpi_print( stdout, generate_public_prime( atoi(argv[0]) ), 1);
putchar('\n');
}
else if( argc == 2 ) {
mpi_print( stdout, generate_elg_prime( atoi(argv[0]),
atoi(argv[1]), NULL ), 1);
putchar('\n');
}
else if( argc == 3 ) {
MPI g = mpi_alloc(1);
mpi_print( stdout, generate_elg_prime( atoi(argv[0]),
atoi(argv[1]), g ), 1);
printf("\nGenerator: ");
mpi_print( stdout, g, 1 );
putchar('\n');
mpi_free(g);
}
else
usage(1);
break;
case aPrintMDs:
if( !argc )
print_mds(NULL);
else {
for(; argc; argc--, argv++ )
print_mds(*argv);
}
break;
case aKeygen: /* generate a key (interactive) */
if( argc )
usage(1);
generate_keypair();
break;
case aTest: do_test( argc? atoi(*argv): 0 ); break;
case aListPackets:
opt.list_packets=1;
default:
if( argc > 1 )
usage(1);
if( !(a = iobuf_open(fname)) )
log_fatal("can't open '%s'\n", fname_print);
if( !opt.no_armor ) {
/* push the armor filter, so it can peek at the input data */
memset( &afx, 0, sizeof afx);
iobuf_push_filter( a, armor_filter, &afx );
}
if( cmd == aListPackets ) {
set_packet_list_mode(1);
opt.list_packets=1;
}
proc_packets( a );
iobuf_close(a);
break;
}
/* cleanup */
FREE_STRLIST(remusr);
FREE_STRLIST(locusr);
return log_get_errorcount(0)? 2:0;
}
static void
print_hex( byte *p, size_t n )
{
int i;
if( n == 20 ) {
for(i=0; i < n ; i++, i++, p += 2 ) {
if( i == 10 )
putchar(' ');
printf(" %02X%02X", *p, p[1] );
}
}
else {
for(i=0; i < n ; i++, p++ ) {
if( i && !(i%8) )
putchar(' ');
printf(" %02X", *p );
}
}
}
static void
print_mds( const char *fname )
{
FILE *fp;
char buf[1024];
size_t n;
MD_HANDLE md;
if( !fname ) {
fp = stdin;
fname = "[stdin]";
}
else
fp = fopen( fname, "rb" );
if( !fp ) {
log_error("%s: %s\n", fname, strerror(errno) );
return;
}
md = md_open( DIGEST_ALGO_MD5, 0 );
md_enable( md, DIGEST_ALGO_RMD160 );
md_enable( md, DIGEST_ALGO_SHA1 );
while( (n=fread( buf, 1, DIM(buf), fp )) )
md_write( md, buf, n );
if( ferror(fp) )
log_error("%s: %s\n", fname, strerror(errno) );
else {
byte *p;
md_final(md);
printf( "%s: MD5 =", fname ); print_hex(md_read(md, DIGEST_ALGO_MD5), 16 );
printf("\n%s: RMD160 =", fname ); print_hex(md_read(md, DIGEST_ALGO_RMD160), 20 );
printf("\n%s: SHA1 =", fname ); print_hex(md_read(md, DIGEST_ALGO_SHA1), 20 );
putchar('\n');
}
md_close(md);
if( fp != stdin )
fclose(fp);
}
static void
do_test(int times)
{
#if 0
MPI t = mpi_alloc( 50 );
MPI m = mpi_alloc( 50 );
MPI a = mpi_alloc( 50 );
MPI b = mpi_alloc( 50 );
MPI p = mpi_alloc( 50 );
MPI x = mpi_alloc( 50 );
/* output = b/(a^x) mod p */
log_debug("invm %d times ", times);
for( ; times > 0; times -- ) {
mpi_fromstr(a, "0xef45678343589854354a4545545454554545455"
"aaaaaaaaaaaaa44444fffdecb33434343443331" );
mpi_fromstr(b, "0x8765765589854354a4545545454554545455"
"aaaaaaa466577778decb36666343443331" );
mpi_invm( t, a, b );
fputc('.', stderr); fflush(stderr);
}
m_check(NULL);
#endif
}
diff --git a/g10/getkey.c b/g10/getkey.c
index 3ec6a6bf4..b1cb64a29 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1,633 +1,706 @@
/* getkey.c - Get a key from the database
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "packet.h"
#include "memory.h"
#include "iobuf.h"
#include "keydb.h"
#include "options.h"
#define MAX_PKC_CACHE_ENTRIES 500
typedef struct keyid_list {
struct keyid_list *next;
u32 keyid[2];
} *keyid_list_t;
typedef struct user_id_db {
struct user_id_db *next;
u32 keyid[2];
int len;
char name[1];
} *user_id_db_t;
typedef struct pkc_cache_entry {
struct pkc_cache_entry *next;
u32 keyid[2];
PKT_public_cert *pkc;
} *pkc_cache_entry_t;
+typedef struct enum_seckey_context {
+ int eof;
+ STRLIST sl;
+ IOBUF iobuf;
+} enum_seckey_context_t;
+
+
static STRLIST keyrings;
static STRLIST secret_keyrings;
static keyid_list_t unknown_keyids;
static user_id_db_t user_id_db;
static pkc_cache_entry_t pkc_cache;
static int pkc_cache_entries; /* number of entries in pkc cache */
static int scan_keyring( PKT_public_cert *pkc, u32 *keyid,
const char *name, const char *filename );
static int scan_secret_keyring( PKT_secret_cert *skc, u32 *keyid,
const char *name, const char *filename);
void
add_keyring( const char *name )
{
STRLIST sl;
int rc;
/* FIXME: check wether this one is available etc */
/* my be we should do this later */
sl = m_alloc( sizeof *sl + strlen(name) );
strcpy(sl->d, name );
sl->next = keyrings;
keyrings = sl;
/* FIXME: We should remove much out of this mpdule and
* combine it with the keyblock stuff from ringedit.c
* For now we will simple add the filename as keyblock resource
*/
rc = add_keyblock_resource( name, 0, 0 );
if( rc )
log_error("keyblock resource '%s': %s\n", name, g10_errstr(rc) );
}
/****************
* Get the name of the keyrings, start with a sequence number of 0.
*/
const char *
get_keyring( int sequence )
{
STRLIST sl;
for(sl = keyrings; sl && sequence; sl = sl->next, sequence-- )
;
return sl? sl->d : NULL;
}
void
add_secret_keyring( const char *name )
{
STRLIST sl;
int rc;
/* FIXME: check wether this one is available etc */
/* my be we should do this later */
sl = m_alloc( sizeof *sl + strlen(name) );
strcpy(sl->d, name );
sl->next = secret_keyrings;
secret_keyrings = sl;
/* FIXME: We should remove much out of this mpdule and
* combine it with the keyblock stuff from ringedit.c
* For now we will simple add the filename as keyblock resource
*/
rc = add_keyblock_resource( name, 0, 1 );
if( rc )
log_error("secret keyblock resource '%s': %s\n", name, g10_errstr(rc) );
}
void
cache_public_cert( PKT_public_cert *pkc )
{
pkc_cache_entry_t ce;
u32 keyid[2];
if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|| pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
keyid_from_pkc( pkc, keyid );
}
else
return; /* don't know how to get the keyid */
for( ce = pkc_cache; ce; ce = ce->next )
if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
if( DBG_CACHE )
log_debug("cache_public_cert: already in cache\n");
return;
}
if( pkc_cache_entries > MAX_PKC_CACHE_ENTRIES ) {
/* FIMXE: use another algorithm to free some cache slots */
if( pkc_cache_entries == MAX_PKC_CACHE_ENTRIES ) {
pkc_cache_entries++;
log_info("too many entries in pkc cache - disabled\n");
}
ce = pkc_cache;
free_public_cert( ce->pkc );
}
else {
pkc_cache_entries++;
ce = m_alloc( sizeof *ce );
ce->next = pkc_cache;
pkc_cache = ce;
}
ce->pkc = copy_public_cert( NULL, pkc );
ce->keyid[0] = keyid[0];
ce->keyid[1] = keyid[1];
}
/****************
* Store the association of keyid and userid
*/
void
cache_user_id( PKT_user_id *uid, u32 *keyid )
{
user_id_db_t r;
for(r=user_id_db; r; r = r->next )
if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
if( DBG_CACHE )
log_debug("cache_user_id: already in cache\n");
return;
}
r = m_alloc( sizeof *r + uid->len-1 );
r->keyid[0] = keyid[0];
r->keyid[1] = keyid[1];
r->len = uid->len;
memcpy(r->name, uid->name, r->len);
r->next = user_id_db;
user_id_db = r;
}
/****************
* Get a public key and store it into the allocated pkc
* can be called with PKC set to NULL to just read it into some
* internal structures.
*/
int
get_pubkey( PKT_public_cert *pkc, u32 *keyid )
{
keyid_list_t kl;
int internal = 0;
int rc = 0;
pkc_cache_entry_t ce;
STRLIST sl;
if( opt.cache_all && !pkc_cache ) {
log_info("reading all entries ...\n");
for(sl = keyrings; sl; sl = sl->next )
if( !scan_keyring( NULL, NULL, NULL, sl->d ) )
goto leave;
log_info("cached %d entries\n", pkc_cache_entries);
}
/* lets see wether we checked the keyid already */
for( kl = unknown_keyids; kl; kl = kl->next )
if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
return G10ERR_NO_PUBKEY; /* already checked and not found */
/* 1. Try to get it from our cache */
for( ce = pkc_cache; ce; ce = ce->next )
if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
if( pkc )
copy_public_cert( pkc, ce->pkc );
return 0;
}
/* more init stuff */
if( !pkc ) {
pkc = m_alloc_clear( sizeof *pkc );
internal++;
}
/* 2. Try to get it from the keyrings */
for(sl = keyrings; sl; sl = sl->next )
if( !scan_keyring( pkc, keyid, NULL, sl->d ) )
goto leave;
/* 3. Try to get it from a key server */
/* 4. not found: store it for future reference */
kl = m_alloc( sizeof *kl );
kl->keyid[0] = keyid[0];
kl->keyid[1] = keyid[1];
kl->next = unknown_keyids;
unknown_keyids = kl;
rc = G10ERR_NO_PUBKEY;
leave:
if( !rc )
cache_public_cert( pkc );
if( internal )
m_free(pkc);
return rc;
}
/****************
* Try to get the pubkey by the userid. This functions looks for the
* first pubkey certificate which has the given name in a user_id.
* if pkc has the pubkey algo set, the function will only return
* a pubkey with that algo.
*/
int
get_pubkey_byname( PKT_public_cert *pkc, const char *name )
{
int internal = 0;
int rc = 0;
STRLIST sl;
if( !pkc ) {
pkc = m_alloc_clear( sizeof *pkc );
internal++;
}
/* 2. Try to get it from the keyrings */
for(sl = keyrings; sl; sl = sl->next )
if( !scan_keyring( pkc, NULL, name, sl->d ) )
goto leave;
/* 3. Try to get it from a key server */
/* 4. not found: store it for future reference */
rc = G10ERR_NO_PUBKEY;
leave:
if( internal )
m_free(pkc);
return rc;
}
/****************
* Get a secret key and store it into skey
*/
int
get_seckey( PKT_secret_cert *skc, u32 *keyid )
{
STRLIST sl;
int rc=0;
for(sl = secret_keyrings; sl; sl = sl->next )
if( !(rc=scan_secret_keyring( skc, keyid, NULL, sl->d )) )
goto found;
/* fixme: look at other places */
goto leave;
found:
/* get the secret key (this may prompt for a passprase to
* unlock the secret key
*/
if( (rc = check_secret_key( skc )) )
goto leave;
leave:
return rc;
}
/****************
* Get a secret key by name and store it into skc
* If NAME is NULL use the default certificate
*/
int
get_seckey_byname( PKT_secret_cert *skc, const char *name, int unprotect )
{
STRLIST sl;
int rc=0;
for(sl = secret_keyrings; sl; sl = sl->next )
if( !(rc=scan_secret_keyring( skc, NULL, name, sl->d ) ) )
goto found;
/* fixme: look at other places */
goto leave;
found:
/* get the secret key (this may prompt for a passprase to
* unlock the secret key
*/
if( unprotect )
if( (rc = check_secret_key( skc )) )
goto leave;
leave:
return rc;
}
+
+
+
/****************
* scan the keyring and look for either the keyid or the name.
*/
static int
scan_keyring( PKT_public_cert *pkc, u32 *keyid,
const char *name, const char *filename )
{
int rc=0;
int found = 0;
IOBUF a;
PACKET pkt;
int save_mode;
u32 akeyid[2];
PKT_public_cert *last_pk = NULL;
assert( !keyid || !name );
if( opt.cache_all && (name || keyid) )
return G10ERR_NO_PUBKEY;
if( !(a = iobuf_open( filename ) ) ) {
log_debug("scan_keyring: can't open '%s'\n", filename );
return G10ERR_KEYRING_OPEN;
}
if( !DBG_CACHE )
;
else if( name )
log_debug("scan_keyring %s for '%s'\n", filename, name );
else if( keyid )
log_debug("scan_keyring %s for %08lx %08lx\n", filename,
keyid[0], keyid[1] );
else
log_debug("scan_keyring %s (all)\n", filename );
save_mode = set_packet_list_mode(0);
init_packet(&pkt);
while( (rc=parse_packet(a, &pkt)) != -1 ) {
if( rc )
; /* e.g. unknown packet */
else if( keyid && found && pkt.pkttype == PKT_PUBLIC_CERT ) {
log_error("Hmmm, pubkey without an user id in '%s'\n", filename);
goto leave;
}
else if( keyid && pkt.pkttype == PKT_PUBLIC_CERT ) {
switch( pkt.pkt.public_cert->pubkey_algo ) {
case PUBKEY_ALGO_ELGAMAL:
case PUBKEY_ALGO_RSA:
keyid_from_pkc( pkt.pkt.public_cert, akeyid );
if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) {
copy_public_cert( pkc, pkt.pkt.public_cert );
found++;
}
break;
default:
log_error("cannot handle pubkey algo %d\n",
pkt.pkt.public_cert->pubkey_algo);
}
}
else if( keyid && found && pkt.pkttype == PKT_USER_ID ) {
cache_user_id( pkt.pkt.user_id, keyid );
goto leave;
}
else if( name && pkt.pkttype == PKT_PUBLIC_CERT ) {
if( last_pk )
free_public_cert(last_pk);
last_pk = pkt.pkt.public_cert;
pkt.pkt.public_cert = NULL;
}
else if( name && pkt.pkttype == PKT_USER_ID ) {
if( memistr( pkt.pkt.user_id->name, pkt.pkt.user_id->len, name )) {
if( !last_pk )
log_error("Ooops: no pubkey for userid '%.*s'\n",
pkt.pkt.user_id->len, pkt.pkt.user_id->name);
else if( pkc->pubkey_algo &&
pkc->pubkey_algo != last_pk->pubkey_algo )
log_info("skipping id '%.*s': want algo %d, found %d\n",
pkt.pkt.user_id->len, pkt.pkt.user_id->name,
pkc->pubkey_algo, last_pk->pubkey_algo );
else {
copy_public_cert( pkc, last_pk );
goto leave;
}
}
}
else if( !keyid && !name && pkt.pkttype == PKT_PUBLIC_CERT ) {
if( last_pk )
free_public_cert(last_pk);
last_pk = pkt.pkt.public_cert;
pkt.pkt.public_cert = NULL;
}
else if( !keyid && !name && pkt.pkttype == PKT_USER_ID ) {
if( !last_pk )
log_error("Ooops: no pubkey for userid '%.*s'\n",
pkt.pkt.user_id->len, pkt.pkt.user_id->name);
else {
if( last_pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|| last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) {
keyid_from_pkc( last_pk, akeyid );
cache_user_id( pkt.pkt.user_id, akeyid );
}
cache_public_cert( last_pk );
}
}
free_packet(&pkt);
}
rc = G10ERR_NO_PUBKEY;
leave:
if( last_pk )
free_public_cert(last_pk);
free_packet(&pkt);
iobuf_close(a);
set_packet_list_mode(save_mode);
return rc;
}
/****************
* This is the function to get a secret key. We use an extra function,
* so that we can easily add special handling for secret keyrings
* PKT returns the secret key certificate.
*/
static int
scan_secret_keyring( PKT_secret_cert *skc, u32 *keyid,
const char *name, const char *filename )
{
int rc=0;
int found = 0;
IOBUF a;
PACKET pkt;
int save_mode;
u32 akeyid[2];
PKT_secret_cert *last_pk = NULL;
int get_first;
u32 dummy_keyid[2];
get_first = !keyid && !name;
if( get_first )
keyid = dummy_keyid;
if( !(a = iobuf_open( filename ) ) ) {
log_debug("scan_secret_keyring: can't open '%s'\n", filename );
return G10ERR_KEYRING_OPEN;
}
save_mode = set_packet_list_mode(0);
init_packet(&pkt);
while( (rc=parse_packet(a, &pkt)) != -1 ) {
if( rc )
; /* e.g. unknown packet */
else if( keyid && found && pkt.pkttype == PKT_SECRET_CERT ) {
log_error("Hmmm, seckey without an user id in '%s'\n", filename);
goto leave;
}
else if( keyid && pkt.pkttype == PKT_SECRET_CERT ) {
switch( pkt.pkt.secret_cert->pubkey_algo ) {
case PUBKEY_ALGO_ELGAMAL:
case PUBKEY_ALGO_RSA:
if( get_first ) {
copy_secret_cert( skc, pkt.pkt.secret_cert );
found++;
}
else {
keyid_from_skc( pkt.pkt.secret_cert, akeyid );
if( (akeyid[0] == keyid[0] && akeyid[1] == keyid[1]) ) {
copy_secret_cert( skc, pkt.pkt.secret_cert );
found++;
}
}
break;
default:
log_error("cannot handle pubkey algo %d\n",
pkt.pkt.secret_cert->pubkey_algo);
}
}
else if( keyid && found && pkt.pkttype == PKT_USER_ID ) {
goto leave;
}
else if( name && pkt.pkttype == PKT_SECRET_CERT ) {
if( last_pk )
free_secret_cert(last_pk);
last_pk = pkt.pkt.secret_cert;
pkt.pkt.secret_cert = NULL;
}
else if( name && pkt.pkttype == PKT_USER_ID ) {
if( memistr( pkt.pkt.user_id->name, pkt.pkt.user_id->len, name )) {
if( !last_pk )
log_error("Ooops: no seckey for userid '%.*s'\n",
pkt.pkt.user_id->len, pkt.pkt.user_id->name);
else if( skc->pubkey_algo &&
skc->pubkey_algo != last_pk->pubkey_algo )
log_info("skipping id '%.*s': want algo %d, found %d\n",
pkt.pkt.user_id->len, pkt.pkt.user_id->name,
skc->pubkey_algo, last_pk->pubkey_algo );
else {
copy_secret_cert( skc, last_pk );
goto leave;
}
}
}
else if( !keyid && !name && pkt.pkttype == PKT_SECRET_CERT ) {
if( last_pk )
free_secret_cert(last_pk);
last_pk = pkt.pkt.secret_cert;
pkt.pkt.secret_cert = NULL;
}
else if( !keyid && !name && pkt.pkttype == PKT_USER_ID ) {
if( !last_pk )
log_error("Ooops: no seckey for userid '%.*s'\n",
pkt.pkt.user_id->len, pkt.pkt.user_id->name);
else {
if( last_pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|| last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) {
keyid_from_skc( last_pk, akeyid );
cache_user_id( pkt.pkt.user_id, akeyid );
}
}
}
free_packet(&pkt);
}
rc = G10ERR_NO_SECKEY;
leave:
if( last_pk )
free_secret_cert(last_pk);
free_packet(&pkt);
iobuf_close(a);
set_packet_list_mode(save_mode);
return rc;
}
+/****************
+ * Enumerate all secret keys. Caller must use these procedure:
+ * 1) create a void pointer and initialize it to NULL
+ * 2) pass this void pointer by reference to this function
+ * and provide space for the secret key (pass a buffer for skc)
+ * 3) call this function as long as it does not return -1
+ * to indicate EOF.
+ * 4) Always call this function a last time with SKC set to NULL,
+ * so that can free it's context.
+ *
+ * Return
+ */
+int
+enum_secret_keys( void **context, PKT_secret_cert *skc )
+{
+ int rc=0;
+ PACKET pkt;
+ int save_mode;
+ enum_seckey_context_t *c = *context;
+
+ if( !c ) { /* make a new context */
+ c = m_alloc_clear( sizeof *c );
+ *context = c;
+ c->sl = secret_keyrings;
+ }
+
+ if( !skc ) { /* free the context */
+ m_free( c );
+ *context = NULL;
+ return 0;
+ }
+
+ if( c->eof )
+ return -1;
+
+ for( ; c->sl; c->sl = c->sl->next ) {
+ if( !c->iobuf ) {
+ if( !(c->iobuf = iobuf_open( c->sl->d ) ) ) {
+ log_error("enum_secret_keys: can't open '%s'\n", c->sl->d );
+ continue; /* try next file */
+ }
+ }
+
+ save_mode = set_packet_list_mode(0);
+ init_packet(&pkt);
+ while( (rc=parse_packet(c->iobuf, &pkt)) != -1 ) {
+ if( rc )
+ ; /* e.g. unknown packet */
+ else if( pkt.pkttype == PKT_SECRET_CERT ) {
+ copy_secret_cert( skc, pkt.pkt.secret_cert );
+ set_packet_list_mode(save_mode);
+ return 0; /* found */
+ }
+ free_packet(&pkt);
+ }
+ set_packet_list_mode(save_mode);
+ iobuf_close(c->iobuf); c->iobuf = NULL;
+ }
+ c->eof = 1;
+ return -1;
+}
+
+
/****************
* Return a string with a printable representation of the user_id.
* this string must be freed by m_free.
*/
char*
get_user_id_string( u32 *keyid )
{
user_id_db_t r;
char *p;
int pass=0;
/* try it two times; second pass reads from keyrings */
do {
for(r=user_id_db; r; r = r->next )
if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
p = m_alloc( r->len + 10 );
sprintf(p, "%08lX %.*s", keyid[1], r->len, r->name );
return p;
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
p = m_alloc( 15 );
sprintf(p, "%08lX [?]", keyid[1] );
return p;
}
char*
get_user_id( u32 *keyid, size_t *rn )
{
user_id_db_t r;
char *p;
int pass=0;
/* try it two times; second pass reads from keyrings */
do {
for(r=user_id_db; r; r = r->next )
if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
p = m_alloc( r->len );
memcpy(p, r->name, r->len );
*rn = r->len;
return p;
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
p = m_alloc( 19 );
memcpy(p, "[User id not found]", 19 );
*rn = 19;
return p;
}
diff --git a/g10/keydb.h b/g10/keydb.h
index 6770f866e..8eb49478d 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -1,141 +1,142 @@
/* keydb.h - Key database
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_KEYDB_H
#define G10_KEYDB_H
#include "types.h"
#include "packet.h"
#include "cipher.h"
/****************
* A Keyblock are all packets which form an entire certificate;
* i.e. the public key, certificate, trust packets, user ids,
* signatures, and subkey.
*
* This structure is also used to bind arbitrary packets together.
*/
typedef struct kbnode_struct *KBNODE;
struct kbnode_struct {
PACKET *pkt;
KBNODE next; /* used to form a link list */
KBNODE child;
int flag;
int private_flag;
};
/****************
* A data structre to hold informations about the external position
* of a keyblock.
*/
struct keyblock_pos_struct {
int resno; /* resource number */
ulong offset; /* position information */
ulong length; /* length of thge keyblock */
int last_block;
};
typedef struct keyblock_pos_struct KBPOS;
/* structure to hold a couple of public key certificates */
typedef struct pkc_list *PKC_LIST;
struct pkc_list {
PKC_LIST next;
PKT_public_cert *pkc;
int mark;
};
/* structure to hold a couple of secret key certificates */
typedef struct skc_list *SKC_LIST;
struct skc_list {
SKC_LIST next;
PKT_secret_cert *skc;
int mark;
};
/*-- pkclist.c --*/
void release_pkc_list( PKC_LIST pkc_list );
int build_pkc_list( STRLIST remusr, PKC_LIST *ret_pkc_list );
/*-- skclist.c --*/
void release_skc_list( SKC_LIST skc_list );
int build_skc_list( STRLIST locusr, SKC_LIST *ret_skc_list, int unlock );
/*-- passphrase.h --*/
void set_passphrase_fd( int fd );
int get_passphrase_fd(void);
DEK *get_passphrase_hash( u32 *keyid, char *text );
int make_dek_from_passphrase( DEK *dek, int mode );
/*-- getkey.c --*/
void add_keyring( const char *name );
const char *get_keyring( int sequence );
void add_secret_keyring( const char *name );
void cache_public_cert( PKT_public_cert *pkc );
void cache_user_id( PKT_user_id *uid, u32 *keyid );
int get_pubkey( PKT_public_cert *pkc, u32 *keyid );
int get_pubkey_byname( PKT_public_cert *pkc, const char *name );
int get_seckey( PKT_secret_cert *skc, u32 *keyid );
int get_seckey_byname( PKT_secret_cert *skc, const char *name, int unlock );
+int enum_secret_keys( void **context, PKT_secret_cert *skc );
char*get_user_id_string( u32 *keyid );
char*get_user_id( u32 *keyid, size_t *rn );
/*-- keyid.c --*/
int pubkey_letter( int algo );
u32 keyid_from_skc( PKT_secret_cert *skc, u32 *keyid );
u32 keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid );
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
unsigned nbits_from_pkc( PKT_public_cert *pkc );
unsigned nbits_from_skc( PKT_secret_cert *skc );
const char *datestr_from_pkc( PKT_public_cert *pkc );
const char *datestr_from_skc( PKT_secret_cert *skc );
const char *datestr_from_sig( PKT_signature *sig );
byte *fingerprint_from_skc( PKT_secret_cert *skc, size_t *ret_len );
byte *fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len );
/*-- kbnode.c --*/
KBNODE new_kbnode( PACKET *pkt );
void release_kbnode( KBNODE n );
void delete_kbnode( KBNODE root, KBNODE node );
void add_kbnode( KBNODE root, KBNODE node );
void add_kbnode_as_child( KBNODE root, KBNODE node );
KBNODE find_kbparent( KBNODE root, KBNODE node );
KBNODE walk_kbtree( KBNODE root, KBNODE *context );
KBNODE walk_kbtree2( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n );
/*-- ringedit.c --*/
int add_keyblock_resource( const char *filename, int force, int secret );
int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos );
int search_keyblock( PACKET *pkt, KBPOS *kbpos, int secret );
int search_keyblock_byname( KBPOS *kbpos, const char *username );
int search_secret_keyblock_byname( KBPOS *kbpos, const char *username );
int lock_keyblock( KBPOS *kbpos );
void unlock_keyblock( KBPOS *kbpos );
int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
int insert_keyblock( KBPOS *kbpos, KBNODE root );
int delete_keyblock( KBPOS *kbpos );
int update_keyblock( KBPOS *kbpos, KBNODE root );
#endif /*G10_KEYDB_H*/
diff --git a/g10/main.h b/g10/main.h
index a10ce4ba3..a1a13e41e 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -1,81 +1,81 @@
/* main.h
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_MAIN_H
#define G10_MAIN_H
#include "types.h"
#include "iobuf.h"
#include "cipher.h"
#include "keydb.h"
typedef struct {
int header_okay;
PKC_LIST pkc_list;
cipher_filter_context_t cfx;
} encrypt_filter_context_t;
/*-- encode.c --*/
int encode_symmetric( const char *filename );
int encode_store( const char *filename );
int encode_crypt( const char *filename, STRLIST remusr );
int encrypt_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len);
/*-- sign.c --*/
-int sign_file( const char *filename, int detached, STRLIST locusr,
- int encrypt, STRLIST remusr );
+int sign_file( STRLIST filenames, int detached, STRLIST locusr,
+ int encrypt, STRLIST remusr, const char *outfile );
int sign_key( const char *username, STRLIST locusr );
int edit_keysigs( const char *username );
int change_passphrase( const char *username );
/*-- sig-check.c --*/
int check_key_signature( KBNODE root, KBNODE node );
/*-- keygen.c --*/
void generate_keypair(void);
/*-- openfile.c --*/
int overwrite_filep( const char *fname );
IOBUF open_outfile( const char *fname, int mode );
IOBUF open_sigfile( const char *iname );
/*-- seskey.c --*/
void make_session_key( DEK *dek );
MPI encode_session_key( DEK *dek, unsigned nbits );
MPI encode_sha1_value( byte *md, unsigned len, unsigned nbits );
MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits );
MPI encode_md5_value( byte *md, unsigned len, unsigned nbits );
MPI encode_md_value( MD_HANDLE md, unsigned nbits );
/*-- comment.c --*/
KBNODE make_comment_node( const char *s );
/*-- elg.c --*/
void g10_elg_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek );
void g10_elg_sign( PKT_secret_cert *skc, PKT_signature *sig, MD_HANDLE md );
/*-- rsa.c --*/
void g10_rsa_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek );
void g10_rsa_sign( PKT_secret_cert *skc, PKT_signature *sig, MD_HANDLE md );
#endif /*G10_MAIN_H*/
diff --git a/g10/options.h b/g10/options.h
index 0df1f41ea..3b72547ce 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -1,68 +1,70 @@
/* options.h
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_OPTIONS_H
#define G10_OPTIONS_H
struct {
int verbose;
unsigned debug;
int armor;
int compress;
char *outfile;
int textmode;
int batch; /* run in batch mode */
int answer_yes; /* answer yes on most questions */
int answer_no; /* answer no on most questions */
int check_sigs; /* check key signatures */
int cache_all;
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
int no_armor;
int list_packets; /* list-packets mode */
int def_cipher_algo;
int def_pubkey_algo;
int def_digest_algo;
int reserved9;
int reserved10;
int reserved11;
int reserved12;
int reserved13;
int reserved14;
int reserved15;
} opt;
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
/* (may reveal sensitive data) */
#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the cacheing */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
+#define DBG_TRUST_VALUE 256 /* debug the trustdb */
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
+#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
#endif /*G10_OPTIONS_H*/
diff --git a/g10/packet.h b/g10/packet.h
index e82248a85..6326c43d4 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -1,267 +1,271 @@
/* packet.h - packet read/write stuff
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_PACKET_H
#define G10_PACKET_H
#include "types.h"
#include "iobuf.h"
#include "mpi.h"
#include "cipher.h"
#include "filter.h"
typedef enum {
PKT_NONE =0,
PKT_PUBKEY_ENC =1, /* public key encrypted packet */
PKT_SIGNATURE =2, /* secret key encrypted packet */
PKT_SESSION_KEY =3, /* session key packet (OpenPGP)*/
PKT_ONEPASS_SIG =4, /* one pass sig packet (OpenPGP)*/
PKT_SECRET_CERT =5, /* secret key certificate */
PKT_PUBLIC_CERT =6, /* public key certificate */
PKT_SECKEY_SUBCERT =7, /* secret subkey certificate (OpenPGP) */
PKT_COMPRESSED =8, /* compressed data packet */
PKT_ENCRYPTED =9, /* conventional encrypted data */
PKT_MARKER =10, /* marker packet (OpenPGP) */
PKT_PLAINTEXT =11, /* plaintext data with filename and mode */
PKT_RING_TRUST =12, /* keyring trust packet */
PKT_USER_ID =13, /* user id packet */
PKT_COMMENT =14, /* comment packet */
PKT_PUBKEY_SUBCERT=14, /* subkey certificate (OpenPGP) */
PKT_NEW_COMMENT =16 /* new comment packet (OpenPGP) */
} pkttype_t;
typedef struct packet_struct PACKET;
typedef struct {
u32 keyid[2]; /* 64 bit keyid */
byte pubkey_algo; /* algorithm used for public key scheme */
union {
struct {
MPI a, b; /* integers with the encrypteded DEK */
} elg;
struct {
MPI rsa_integer; /* integer containing the DEK */
} rsa;
} d;
} PKT_pubkey_enc;
typedef struct {
u32 keyid[2]; /* 64 bit keyid */
byte sig_class; /* sig classification */
byte digest_algo; /* algorithm used for digest */
byte pubkey_algo; /* algorithm used for public key scheme */
byte last; /* a stupid flag */
} PKT_onepass_sig;
typedef struct {
u32 keyid[2]; /* 64 bit keyid */
u32 timestamp; /* signature made */
byte sig_class; /* sig classification, append for MD calculation*/
byte pubkey_algo; /* algorithm used for public key scheme */
/* (PUBKEY_ALGO_xxx) */
union {
struct {
byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
byte digest_start[2]; /* first 2 byte of the digest */
MPI a, b; /* integers with the digest */
} elg;
struct {
byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
byte digest_start[2]; /* first 2 byte of the digest */
MPI rsa_integer; /* the encrypted digest */
} rsa;
} d;
} PKT_signature;
typedef struct {
u32 timestamp; /* certificate made */
u16 valid_days; /* valid for this number of days */
byte pubkey_algo; /* algorithm used for public key scheme */
md_filter_context_t mfx;
+ u32 local_id; /* internal use, valid if > 0 */
union {
struct {
MPI p; /* prime */
MPI g; /* group generator */
MPI y; /* g^x mod p */
} elg;
struct {
MPI rsa_n; /* public modulus */
MPI rsa_e; /* public exponent */
} rsa;
} d;
} PKT_public_cert;
typedef struct {
u32 timestamp; /* certificate made */
u16 valid_days; /* valid for this number of days */
byte pubkey_algo; /* algorithm used for public key scheme */
union {
struct {
MPI p; /* prime */
MPI g; /* group generator */
MPI y; /* g^x mod p */
MPI x; /* secret exponent */
u16 csum; /* checksum */
byte is_protected; /* The above infos are protected and must */
/* be decrypteded before use */
byte protect_algo; /* cipher used to protect the secret informations*/
union { /* information for the protection */
struct {
byte iv[8]; /* initialization vector for CFB mode */
/* when protected, the MPIs above are pointers
* to plain storage */
} blowfish;
} protect;
} elg;
struct {
MPI rsa_n; /* public modulus */
MPI rsa_e; /* public exponent */
MPI rsa_d; /* secret descryption exponent */
MPI rsa_p; /* secret first prime number */
MPI rsa_q; /* secret second prime number */
MPI rsa_u; /* secret multiplicative inverse */
u16 csum; /* checksum */
byte is_protected; /* The above infos are protected and must */
/* be decrypteded before use */
byte protect_algo; /* cipher used to protect the secret informations*/
union { /* information for the protection */
struct {
byte iv[8]; /* initialization vector for CFB mode */
/* when protected, the MPIs above are pointers
* to plain storage */
} blowfish;
} protect;
} rsa;
} d;
} PKT_secret_cert;
typedef struct {
int len; /* length of data */
char data[1];
} PKT_comment;
typedef struct {
int len; /* length of the name */
char name[1];
} PKT_user_id;
typedef struct {
u32 len; /* reserved */
byte algorithm;
IOBUF buf; /* IOBUF reference */
} PKT_compressed;
typedef struct {
u32 len; /* length of encrypted data */
IOBUF buf; /* IOBUF reference */
} PKT_encrypted;
typedef struct {
u32 len; /* length of encrypted data */
IOBUF buf; /* IOBUF reference */
int mode;
u32 timestamp;
int namelen;
char name[1];
} PKT_plaintext;
/* combine all packets into a union */
struct packet_struct {
pkttype_t pkttype;
union {
void *generic;
PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */
PKT_signature *signature; /* PKT_SIGNATURE */
PKT_public_cert *public_cert; /* PKT_PUBLIC_CERT */
PKT_secret_cert *secret_cert; /* PKT_SECRET_CERT */
PKT_comment *comment; /* PKT_COMMENT */
PKT_user_id *user_id; /* PKT_USER_ID */
PKT_compressed *compressed; /* PKT_COMPRESSED */
PKT_encrypted *encrypted; /* PKT_ENCRYPTED */
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
} pkt;
};
#define init_packet(a) do { (a)->pkttype = 0; \
(a)->pkt.generic = NULL; \
} while(0)
/*-- mainproc.c --*/
int proc_packets( IOBUF a );
int list_packets( IOBUF a );
/*-- parse-packet.c --*/
int set_packet_list_mode( int mode );
int search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos );
int parse_packet( IOBUF inp, PACKET *ret_pkt);
/*-- build-packet.c --*/
int build_packet( IOBUF inp, PACKET *pkt );
u32 calc_packet_length( PACKET *pkt );
void hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc );
/*-- free-packet.c --*/
void free_pubkey_enc( PKT_pubkey_enc *enc );
void free_seckey_enc( PKT_signature *enc );
+void release_public_cert_parts( PKT_public_cert *cert );
void free_public_cert( PKT_public_cert *cert );
+void release_secret_cert_parts( PKT_secret_cert *cert );
void free_secret_cert( PKT_secret_cert *cert );
void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
PKT_public_cert *copy_public_cert( PKT_public_cert *d, PKT_public_cert *s );
PKT_secret_cert *copy_secret_cert( PKT_secret_cert *d, PKT_secret_cert *s );
+int cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc );
/*-- sig-check.c --*/
int signature_check( PKT_signature *sig, MD_HANDLE digest );
/*-- seckey-cert.c --*/
int is_secret_key_protected( PKT_secret_cert *cert );
int check_secret_key( PKT_secret_cert *cert );
int protect_secret_key( PKT_secret_cert *cert, DEK *dek );
/*-- pubkey-enc.c --*/
int get_session_key( PKT_pubkey_enc *k, DEK *dek );
/*-- compress.c --*/
int handle_compressed( PKT_compressed *zd );
/*-- encr-data.c --*/
int decrypt_data( PKT_encrypted *ed, DEK *dek );
int encrypt_data( PKT_encrypted *ed, DEK *dek );
/*-- plaintext.c --*/
int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx );
int ask_for_detached_datafile( md_filter_context_t *mfx, const char *inname );
/*-- comment.c --*/
int write_comment( IOBUF out, const char *s );
/*-- sign.c --*/
int make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc,
PKT_user_id *uid, PKT_secret_cert *skc,
int sigclass, int digest_algo );
#endif /*G10_PACKET_H*/
diff --git a/g10/pkclist.c b/g10/pkclist.c
index f753eb6fc..3fd22549c 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1,125 +1,145 @@
/* pkclist.c
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "trustdb.h"
/****************
* Check wether we can trust this pkc which has a trustlevel of TRUSTLEVEL
* Returns: true if we trust.
*/
static int
do_we_trust( PKT_public_cert *pkc, int trustlevel )
{
+ int rc;
+
+ if( trustlevel & TRUST_NO_PUBKEY ) {
+ /* No pubkey in trustDB: Insert and check again */
+ rc = insert_trust_record( pkc );
+ if( rc ) {
+ log_error("failed to insert it into the trustdb: %s\n",
+ g10_errstr(rc) );
+ return 0; /* no */
+ }
+ rc = check_pkc_trust( pkc, &trustlevel );
+ if( rc )
+ log_fatal("trust check after insert failed: %s\n",
+ g10_errstr(rc) );
+ if( trustlevel & TRUST_NO_PUBKEY )
+ log_bug(NULL);
+ }
+
+
/* Eventuell fragen falls der trustlevel nicht ausreichend ist */
return 1; /* yes */
}
void
release_pkc_list( PKC_LIST pkc_list )
{
PKC_LIST pkc_rover;
for( ; pkc_list; pkc_list = pkc_rover ) {
pkc_rover = pkc_list->next;
free_public_cert( pkc_list->pkc );
m_free( pkc_list );
}
}
int
build_pkc_list( STRLIST remusr, PKC_LIST *ret_pkc_list )
{
PKC_LIST pkc_list = NULL;
PKC_LIST pkc_rover = NULL;
int rc;
if( !remusr ) { /* ask!!! */
log_bug("ask for public key nyi\n");
}
else {
for(; remusr; remusr = remusr->next ) {
PKT_public_cert *pkc;
pkc = m_alloc_clear( sizeof *pkc );
if( (rc = get_pubkey_byname( pkc, remusr->d )) ) {
free_public_cert( pkc ); pkc = NULL;
log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
}
else if( !(rc=check_pubkey_algo(pkc->pubkey_algo)) ) {
int trustlevel;
rc = check_pkc_trust( pkc, &trustlevel );
if( rc ) {
free_public_cert( pkc ); pkc = NULL;
log_error("error checking pkc of '%s': %s\n",
remusr->d, g10_errstr(rc) );
}
else if( do_we_trust( pkc, trustlevel ) ) {
+ /* note: do_we_trust may have changed the trustlevel */
PKC_LIST r;
r = m_alloc( sizeof *r );
r->pkc = pkc; pkc = NULL;
r->next = pkc_list;
r->mark = 0;
pkc_list = r;
}
else { /* we don't trust this pkc */
free_public_cert( pkc ); pkc = NULL;
}
}
else {
free_public_cert( pkc ); pkc = NULL;
log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
}
}
}
if( !rc && !pkc_list ) {
log_error("no valid addressees\n");
rc = G10ERR_NO_USER_ID;
}
if( rc )
release_pkc_list( pkc_list );
else
*ret_pkc_list = pkc_list;
return rc;
}
diff --git a/g10/sign.c b/g10/sign.c
index 04ae72a2f..9e8275ae9 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1,864 +1,915 @@
/* sign.c - sign data
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "filter.h"
#include "ttyio.h"
static int
complete_sig( PKT_signature *sig, PKT_secret_cert *skc, MD_HANDLE md )
{
int rc=0;
if( (rc=check_secret_key( skc )) )
;
else if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
g10_elg_sign( skc, sig, md );
else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
g10_rsa_sign( skc, sig, md );
else
log_bug(NULL);
/* fixme: should we check wether the signature is okay? */
return rc;
}
/****************
- * Sign the file with name FILENAME. If DETACHED has the value true,
- * make a detached signature. If FILENAME is NULL read from stdin
+ * Sign the files whose names are in FILENAME.
+ * If DETACHED has the value true,
+ * make a detached signature. If FILENAMES->d is NULL read from stdin
* and ignore the detached mode. Sign the file with all secret keys
* which can be taken from LOCUSR, if this is NULL, use the default one
* If ENCRYPT is true, use REMUSER (or ask if it is NULL) to encrypt the
* signed data for these users.
+ * If OUTFILE is not NULL; this file is used for output and the function
+ * does not ask for overwrite permission; output is then always
+ * uncompressed, non-armored and in binary mode.
*/
int
-sign_file( const char *filename, int detached, STRLIST locusr,
- int encrypt, STRLIST remusr )
+sign_file( STRLIST filenames, int detached, STRLIST locusr,
+ int encrypt, STRLIST remusr, const char *outfile )
{
+ const char *fname;
armor_filter_context_t afx;
compress_filter_context_t zfx;
md_filter_context_t mfx;
text_filter_context_t tfx;
encrypt_filter_context_t efx;
IOBUF inp = NULL, out = NULL;
PACKET pkt;
PKT_plaintext *pt = NULL;
u32 filesize;
int last_rc, rc = 0;
PKC_LIST pkc_list = NULL;
SKC_LIST skc_list = NULL;
SKC_LIST skc_rover = NULL;
+ int multifile = 0;
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
memset( &mfx, 0, sizeof mfx);
memset( &tfx, 0, sizeof tfx);
memset( &efx, 0, sizeof efx);
init_packet( &pkt );
+ if( filenames ) {
+ fname = filenames->d;
+ multifile = !!filenames->next;
+ }
+ else
+ fname = NULL;
+
+ if( fname && filenames->next && (!detached || encrypt) )
+ log_bug("multiple files can only be detached signed");
+
if( (rc=build_skc_list( locusr, &skc_list, 1 )) )
goto leave;
if( encrypt ) {
if( (rc=build_pkc_list( remusr, &pkc_list )) )
goto leave;
}
/* prepare iobufs */
- if( !(inp = iobuf_open(filename)) ) {
- log_error("can't open %s: %s\n", filename? filename: "[stdin]",
+ if( multifile ) /* have list of filenames */
+ inp = NULL; /* we do it later */
+ else if( !(inp = iobuf_open(fname)) ) {
+ log_error("can't open %s: %s\n", fname? fname: "[stdin]",
strerror(errno) );
rc = G10ERR_OPEN_FILE;
goto leave;
}
- if( !(out = open_outfile( filename, opt.armor? 1: detached? 2:0 )) ) {
+ if( outfile ) {
+ if( !(out = iobuf_create( outfile )) ) {
+ log_error("can't create %s: %s\n", outfile, strerror(errno) );
+ rc = G10ERR_CREATE_FILE;
+ goto leave;
+ }
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", outfile );
+ }
+ else if( !(out = open_outfile( fname, opt.armor? 1: detached? 2:0 )) ) {
rc = G10ERR_CREATE_FILE;
goto leave;
}
/* prepare to calculate the MD over the input */
- if( opt.textmode && opt.armor )
+ if( opt.textmode && opt.armor && !outfile )
iobuf_push_filter( inp, text_filter, &tfx );
mfx.md = md_open(DIGEST_ALGO_RMD160, 0);
- iobuf_push_filter( inp, md_filter, &mfx );
+ if( !multifile )
+ iobuf_push_filter( inp, md_filter, &mfx );
- if( opt.armor )
+ if( opt.armor && !outfile )
iobuf_push_filter( out, armor_filter, &afx );
write_comment( out, "#Created by G10 pre-release " VERSION );
- if( opt.compress )
+ if( opt.compress && !outfile )
iobuf_push_filter( out, compress_filter, &zfx );
if( encrypt ) {
efx.pkc_list = pkc_list;
/* fixme: set efx.cfx.datalen if known */
iobuf_push_filter( out, encrypt_filter, &efx );
}
/* loop over the secret certificates and build headers */
for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) {
PKT_secret_cert *skc;
PKT_onepass_sig *ops;
skc = skc_rover->skc;
ops = m_alloc_clear( sizeof *ops );
- ops->sig_class = opt.textmode? 0x01 : 0x00;
+ ops->sig_class = opt.textmode && !outfile ? 0x01 : 0x00;
ops->digest_algo = DIGEST_ALGO_RMD160;
ops->pubkey_algo = skc->pubkey_algo;
keyid_from_skc( skc, ops->keyid );
ops->last = !skc_rover->next;
init_packet(&pkt);
pkt.pkttype = PKT_ONEPASS_SIG;
pkt.pkt.onepass_sig = ops;
rc = build_packet( out, &pkt );
free_packet( &pkt );
if( rc ) {
log_error("build onepass_sig packet failed: %s\n", g10_errstr(rc));
goto leave;
}
}
/* setup the inner packet */
if( detached ) {
- /* read, so that the filter can calculate the digest */
- while( iobuf_get(inp) != -1 )
- ;
+ if( multifile ) {
+ STRLIST sl = filenames;
+
+ if( opt.verbose )
+ log_info("signing:" );
+ for(; sl; sl = sl->next ) {
+ if( !(inp = iobuf_open(sl->d)) ) {
+ log_error("can't open %s: %s\n", sl->d, strerror(errno) );
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+ if( opt.verbose )
+ fprintf(stderr, " '%s'", sl->d );
+ iobuf_push_filter( inp, md_filter, &mfx );
+ while( iobuf_get(inp) != -1 )
+ ;
+ iobuf_close(inp); inp = NULL;
+ }
+ if( opt.verbose )
+ putc( '\n', stderr );
+ }
+ else {
+ /* read, so that the filter can calculate the digest */
+ while( iobuf_get(inp) != -1 )
+ ;
+ }
}
else {
- if( filename ) {
- pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
- pt->namelen = strlen(filename);
- memcpy(pt->name, filename, pt->namelen );
+ if( fname ) {
+ pt = m_alloc( sizeof *pt + strlen(fname) - 1 );
+ pt->namelen = strlen(fname);
+ memcpy(pt->name, fname, pt->namelen );
if( !(filesize = iobuf_get_filelength(inp)) )
- log_info("warning: '%s' is an empty file\n", filename );
+ log_info("warning: '%s' is an empty file\n", fname );
}
else { /* no filename */
pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
filesize = 0; /* stdin */
}
pt->timestamp = make_timestamp();
- pt->mode = opt.textmode? 't':'b';
+ pt->mode = opt.textmode && !outfile ? 't':'b';
pt->len = filesize;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
/*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/
if( (rc = build_packet( out, &pkt )) )
log_error("build_packet(PLAINTEXT) failed: %s\n", g10_errstr(rc) );
pt->buf = NULL;
}
/* loop over the secret certificates */
for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) {
PKT_secret_cert *skc;
PKT_signature *sig;
MD_HANDLE md;
byte *dp;
skc = skc_rover->skc;
/* build the signature packet */
sig = m_alloc_clear( sizeof *sig );
sig->pubkey_algo = skc->pubkey_algo;
sig->timestamp = make_timestamp();
- sig->sig_class = opt.textmode? 0x01 : 0x00;
+ sig->sig_class = opt.textmode && !outfile? 0x01 : 0x00;
md = md_copy( mfx.md );
md_putc( md, sig->sig_class );
{ u32 a = sig->timestamp;
md_putc( md, (a >> 24) & 0xff );
md_putc( md, (a >> 16) & 0xff );
md_putc( md, (a >> 8) & 0xff );
md_putc( md, a & 0xff );
}
md_final( md );
dp = md_read( md, DIGEST_ALGO_RMD160 );
if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
ELG_secret_key skey;
MPI frame;
keyid_from_skc( skc, sig->keyid );
sig->d.elg.digest_algo = DIGEST_ALGO_RMD160;
sig->d.elg.digest_start[0] = dp[0];
sig->d.elg.digest_start[1] = dp[1];
sig->d.elg.a = mpi_alloc( mpi_get_nlimbs(skc->d.elg.p) );
sig->d.elg.b = mpi_alloc( mpi_get_nlimbs(skc->d.elg.p) );
frame = encode_rmd160_value( dp, 20, mpi_get_nbits(skc->d.elg.p) );
skey.p = skc->d.elg.p;
skey.g = skc->d.elg.g;
skey.y = skc->d.elg.y;
skey.x = skc->d.elg.x;
elg_sign( sig->d.elg.a, sig->d.elg.b, frame, &skey);
memset( &skey, 0, sizeof skey );
mpi_free(frame);
if( opt.verbose ) {
char *ustr = get_user_id_string( sig->keyid );
log_info("ELG signature from: %s\n", ustr );
m_free(ustr);
}
}
#ifdef HAVE_RSA_CIPHER
else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
RSA_secret_key skey;
keyid_from_skc( skc, sig->keyid );
sig->d.rsa.digest_algo = DIGEST_ALGO_RMD160;
sig->d.rsa.digest_start[0] = dp[0];
sig->d.rsa.digest_start[1] = dp[1];
sig->d.rsa.rsa_integer = encode_rmd160_value( dp, 20,
mpi_get_nbits(skc->d.rsa.rsa_n) );
skey.e = skc->d.rsa.rsa_e;
skey.n = skc->d.rsa.rsa_n;
skey.p = skc->d.rsa.rsa_p;
skey.q = skc->d.rsa.rsa_q;
skey.d = skc->d.rsa.rsa_d;
skey.u = skc->d.rsa.rsa_u;
rsa_secret( sig->d.rsa.rsa_integer, sig->d.rsa.rsa_integer, &skey);
memset( &skey, 0, sizeof skey );
if( opt.verbose ) {
char *ustr = get_user_id_string( sig->keyid );
log_info("RSA signature from: %s\n", ustr );
m_free(ustr);
}
/* fixme: should we check wether the signature is okay? */
}
#endif/*HAVE_RSA_CIPHER*/
else
log_bug(NULL);
md_close( md );
/* and write it */
init_packet(&pkt);
pkt.pkttype = PKT_SIGNATURE;
pkt.pkt.signature = sig;
rc = build_packet( out, &pkt );
free_packet( &pkt );
if( rc ) {
log_error("build signature packet failed: %s\n", g10_errstr(rc) );
goto leave;
}
}
leave:
if( rc )
iobuf_cancel(out);
else
iobuf_close(out);
iobuf_close(inp);
md_close( mfx.md );
release_skc_list( skc_list );
release_pkc_list( pkc_list );
return rc;
}
static void
show_fingerprint( PKT_public_cert *pkc )
{
byte *array, *p;
size_t i, n;
p = array = fingerprint_from_pkc( pkc, &n );
tty_printf(" Fingerprint:");
if( n == 20 ) {
for(i=0; i < n ; i++, i++, p += 2 ) {
if( i == 10 )
tty_printf(" ");
tty_printf(" %02X%02X", *p, p[1] );
}
}
else {
for(i=0; i < n ; i++, p++ ) {
if( i && !(i%8) )
tty_printf(" ");
tty_printf(" %02X", *p );
}
}
tty_printf("\n");
m_free(array);
}
/****************
* Ask wether the user is willing to sign the key. Return true if so.
*/
static int
sign_it_p( PKT_public_cert *pkc, PKT_user_id *uid )
{
char *answer;
int yes;
tty_printf("\nAre you really sure that you want so sign this key:\n\n"
"%4u%c/%08lX %s ",
nbits_from_pkc( pkc ),
pubkey_letter( pkc->pubkey_algo ),
(ulong)keyid_from_pkc( pkc, NULL ),
datestr_from_pkc( pkc ) );
tty_print_string( uid->name, uid->len );
tty_printf("\n");
show_fingerprint(pkc);
tty_printf("\n");
answer = tty_get("Sign this key? ");
tty_kill_prompt();
yes = answer_is_yes(answer);
m_free(answer);
return yes;
}
/****************
* Check the keysigs and set the flags to indicate errors.
* Usage of nodes flag bits:
* Bit 0 = bad signature
* 1 = no public key
* 2 = other error
* Returns true if error found.
*/
static int
check_all_keysigs( KBNODE keyblock )
{
KBNODE kbctx;
KBNODE node;
int rc;
int inv_sigs = 0;
int no_key = 0;
int oth_err = 0;
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
PKT_signature *sig = node->pkt->pkt.signature;
int sigrc;
tty_printf("sig");
switch( (rc = check_key_signature( keyblock, node )) ) {
case 0: node->flag = 0; sigrc = '!'; break;
case G10ERR_BAD_SIGN: inv_sigs++; node->flag = 1; sigrc = '-'; break;
case G10ERR_NO_PUBKEY: no_key++; node->flag = 2; sigrc = '?'; break;
default: oth_err++; node->flag = 4; sigrc = '%'; break;
}
tty_printf("%c %08lX %s ",
sigrc, sig->keyid[1], datestr_from_sig(sig));
if( sigrc == '%' )
tty_printf("[%s] ", g10_errstr(rc) );
else if( sigrc == '?' )
;
else {
size_t n;
char *p = get_user_id( sig->keyid, &n );
tty_print_string( p, n > 40? 40 : n );
m_free(p);
}
tty_printf("\n");
/* FIXME: update the trustdb */
}
}
if( inv_sigs )
tty_printf("%d bad signatures\n", inv_sigs );
if( no_key )
tty_printf("No public key for %d signatures\n", no_key );
if( oth_err )
tty_printf("%d signatures not checked due to errors\n", oth_err );
return inv_sigs || no_key || oth_err;
}
/****************
* Ask and remove invalid signatures are to be removed.
*/
static int
remove_keysigs( KBNODE keyblock, int all )
{
KBNODE kbctx;
KBNODE node;
char *answer;
int yes;
int count;
count = 0;
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( ((node->flag & 7) || all )
&& node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
PKT_signature *sig = node->pkt->pkt.signature;
int sigrc;
if( all ) {
/* fixme: skip self-sig */
}
tty_printf("\n \"%08lX %s ",
sig->keyid[1], datestr_from_sig(sig));
if( node->flag & 6 )
tty_printf("[User name not available] ");
else {
size_t n;
char *p = get_user_id( sig->keyid, &n );
tty_print_string( p, n );
m_free(p);
}
tty_printf("\"\n");
if( node->flag & 1 )
tty_printf("This is a BAD signature!\n");
else if( node->flag & 2 )
tty_printf("Public key not available.\n");
else if( node->flag & 4 )
tty_printf("The signature could not be checked!\n");
answer = tty_get("\nRemove this signature? ");
tty_kill_prompt();
if( answer_is_yes(answer) ) {
node->flag |= 128; /* use bit 7 to mark this node */
count++;
}
m_free(answer);
}
}
if( !count )
return 0; /* nothing to remove */
answer = tty_get("Do you really want to remove the selected signatures? ");
tty_kill_prompt();
yes = answer_is_yes(answer);
m_free(answer);
if( !yes )
return 0;
for( kbctx=NULL; (node=walk_kbtree2( keyblock, &kbctx, 1)) ; ) {
if( node->flag & 128)
delete_kbnode( keyblock, node );
}
return 1;
}
/****************
* This functions signs the key of USERNAME with all users listed in
* LOCUSR. If LOCUSR is NULL the default secret certificate will
* be used. This works on all keyrings, so there is no armor or
* compress stuff here.
*/
int
sign_key( const char *username, STRLIST locusr )
{
md_filter_context_t mfx;
int rc = 0;
SKC_LIST skc_list = NULL;
SKC_LIST skc_rover = NULL;
KBNODE keyblock = NULL;
KBNODE kbctx, node;
KBPOS kbpos;
PKT_public_cert *pkc;
int any;
u32 pkc_keyid[2];
char *answer;
memset( &mfx, 0, sizeof mfx);
/* search the userid */
rc = search_keyblock_byname( &kbpos, username );
if( rc ) {
log_error("user '%s' not found\n", username );
goto leave;
}
/* build a list of all signators */
rc=build_skc_list( locusr, &skc_list, 0 );
if( rc )
goto leave;
/* read the keyblock */
rc = read_keyblock( &kbpos, &keyblock );
if( rc ) {
log_error("error reading the certificate: %s\n", g10_errstr(rc) );
goto leave;
}
/* get the keyid from the keyblock */
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_PUBLIC_CERT )
break;
}
if( !node ) {
log_error("Oops; public key not found anymore!\n");
rc = G10ERR_GENERAL;
goto leave;
}
pkc = node->pkt->pkt.public_cert;
keyid_from_pkc( pkc, pkc_keyid );
log_info("Checking signatures of this public key certificate:\n");
tty_printf("pub %4u%c/%08lX %s ",
nbits_from_pkc( pkc ),
pubkey_letter( pkc->pubkey_algo ),
pkc_keyid[1], datestr_from_pkc(pkc) );
{
size_t n;
char *p = get_user_id( pkc_keyid, &n );
tty_print_string( p, n > 40? 40 : n );
m_free(p);
tty_printf("\n");
}
clear_kbnode_flags( keyblock );
if( check_all_keysigs( keyblock ) ) {
if( !opt.batch ) {
/* ask wether we really should do anything */
answer = tty_get("To you want to remove some of the invalid sigs? ");
tty_kill_prompt();
if( answer_is_yes(answer) )
remove_keysigs( keyblock, 0 );
m_free(answer);
}
}
/* check wether we have already signed it */
for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) {
u32 akeyid[2];
keyid_from_skc( skc_rover->skc, akeyid );
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
if( akeyid[0] == node->pkt->pkt.signature->keyid[0]
&& akeyid[1] == node->pkt->pkt.signature->keyid[1] ) {
log_info("Already signed by keyid %08lX\n", akeyid[1] );
skc_rover->mark = 1;
}
}
}
}
for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) {
if( !skc_rover->mark )
break;
}
if( !skc_rover ) {
log_info("Nothing to sign\n");
goto leave;
}
/* Loop over all signers and all user ids and sign */
for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) {
if( skc_rover->mark )
continue;
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_USER_ID ) {
if( sign_it_p( pkc, node->pkt->pkt.user_id ) ) {
PACKET *pkt;
PKT_signature *sig;
rc = make_keysig_packet( &sig, pkc,
node->pkt->pkt.user_id,
skc_rover->skc,
0x10,
DIGEST_ALGO_RMD160 );
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc));
goto leave;
}
pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode_as_child( node, new_kbnode( pkt ) );
}
}
}
}
rc = update_keyblock( &kbpos, keyblock );
if( rc ) {
log_error("update_keyblock failed: %s\n", g10_errstr(rc) );
goto leave;
}
leave:
release_kbnode( keyblock );
release_skc_list( skc_list );
md_close( mfx.md );
return rc;
}
int
edit_keysigs( const char *username )
{
int rc = 0;
KBNODE keyblock = NULL;
KBNODE kbctx, node;
KBPOS kbpos;
PKT_public_cert *pkc;
int any;
u32 pkc_keyid[2];
char *answer;
/* search the userid */
rc = search_keyblock_byname( &kbpos, username );
if( rc ) {
log_error("user '%s' not found\n", username );
goto leave;
}
/* read the keyblock */
rc = read_keyblock( &kbpos, &keyblock );
if( rc ) {
log_error("error reading the certificate: %s\n", g10_errstr(rc) );
goto leave;
}
/* get the keyid from the keyblock */
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_PUBLIC_CERT )
break;
}
if( !node ) {
log_error("Oops; public key not found anymore!\n");
rc = G10ERR_GENERAL;
goto leave;
}
pkc = node->pkt->pkt.public_cert;
keyid_from_pkc( pkc, pkc_keyid );
log_info("Checking signatures of this public key certificate:\n");
tty_printf("pub %4u%c/%08lX %s ",
nbits_from_pkc( pkc ),
pubkey_letter( pkc->pubkey_algo ),
pkc_keyid[1], datestr_from_pkc(pkc) );
{
size_t n;
char *p = get_user_id( pkc_keyid, &n );
tty_print_string( p, n > 40? 40 : n );
m_free(p);
tty_printf("\n");
}
clear_kbnode_flags( keyblock );
check_all_keysigs( keyblock );
if( remove_keysigs( keyblock, 1 ) ) {
rc = update_keyblock( &kbpos, keyblock );
if( rc ) {
log_error("update_keyblock failed: %s\n", g10_errstr(rc) );
goto leave;
}
}
leave:
release_kbnode( keyblock );
return rc;
}
int
change_passphrase( const char *username )
{
int rc = 0;
KBNODE keyblock = NULL;
KBNODE kbctx, node;
KBPOS kbpos;
PKT_secret_cert *skc;
int any;
u32 skc_keyid[2];
char *answer;
int changed=0;
/* search the userid */
rc = search_secret_keyblock_byname( &kbpos, username );
if( rc ) {
log_error("secret key for user '%s' not found\n", username );
goto leave;
}
/* read the keyblock */
rc = read_keyblock( &kbpos, &keyblock );
if( rc ) {
log_error("error reading the certificate: %s\n", g10_errstr(rc) );
goto leave;
}
/* get the keyid from the keyblock */
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_SECRET_CERT )
break;
}
if( !node ) {
log_error("Oops; secret key not found anymore!\n");
rc = G10ERR_GENERAL;
goto leave;
}
skc = node->pkt->pkt.secret_cert;
keyid_from_skc( skc, skc_keyid );
tty_printf("sec %4u%c/%08lX %s ",
nbits_from_skc( skc ),
pubkey_letter( skc->pubkey_algo ),
skc_keyid[1], datestr_from_skc(skc) );
{
size_t n;
char *p = get_user_id( skc_keyid, &n );
tty_print_string( p, n );
m_free(p);
tty_printf("\n");
}
clear_kbnode_flags( keyblock );
switch( is_secret_key_protected( skc ) ) {
case -1:
rc = G10ERR_PUBKEY_ALGO;
break;
case 0:
tty_printf("This key is not protected.\n");
break;
default:
tty_printf("Key is protected.\n");
rc = check_secret_key( skc );
break;
}
if( rc )
tty_printf("Can't edit this key: %s\n", g10_errstr(rc));
else {
DEK *dek = m_alloc_secure( sizeof *dek );
tty_printf( "Enter the new passphrase for this secret key.\n\n" );
for(;;) {
dek->algo = CIPHER_ALGO_BLOWFISH;
rc = make_dek_from_passphrase( dek , 2 );
if( rc == -1 ) {
rc = 0;
tty_printf( "You don't want a passphrase -"
" this is probably a *bad* idea!\n\n");
answer = tty_get("Do you really want to do this? ");
tty_kill_prompt();
if( answer_is_yes(answer) )
changed++;
m_free(answer);
break;
}
else if( rc == G10ERR_PASSPHRASE ) {
tty_printf("passphrase not correctly repeated; try again.\n");
}
else if( rc ) {
m_free(dek); dek = NULL;
log_error("Error getting the passphrase: %s\n", g10_errstr(rc));
break;
}
else { /* okay */
skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
rc = protect_secret_key( skc, dek );
if( rc )
log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
else
changed++;
break;
}
}
m_free(dek);
}
if( changed ) {
rc = update_keyblock( &kbpos, keyblock );
if( rc ) {
log_error("update_keyblock failed: %s\n", g10_errstr(rc) );
goto leave;
}
}
leave:
release_kbnode( keyblock );
return rc;
}
/****************
* Create a signature packet for the given public key certificate
* and the user id and return it in ret_sig. User signature class SIGCLASS
*/
int
make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc,
PKT_user_id *uid, PKT_secret_cert *skc,
int sigclass, int digest_algo )
{
PKT_signature *sig;
int rc=0;
MD_HANDLE md;
assert( sigclass >= 0x10 && sigclass <= 0x13 );
md = md_open( digest_algo, 0 );
/* hash the public key certificate */
hash_public_cert( md, pkc );
md_write( md, uid->name, uid->len );
/* and make the signature packet */
sig = m_alloc_clear( sizeof *sig );
sig->pubkey_algo = skc->pubkey_algo;
sig->timestamp = make_timestamp();
sig->sig_class = sigclass;
md_putc( md, sig->sig_class );
{ u32 a = sig->timestamp;
md_putc( md, (a >> 24) & 0xff );
md_putc( md, (a >> 16) & 0xff );
md_putc( md, (a >> 8) & 0xff );
md_putc( md, a & 0xff );
}
rc = complete_sig( sig, skc, md );
md_close( md );
if( rc )
free_seckey_enc( sig );
else
*ret_sig = sig;
return rc;
}
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 46c950021..1dfaaa570 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -1,245 +1,821 @@
/* trustdb.c
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
+#include <fcntl.h>
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "trustdb.h"
#include "options.h"
#define TRUST_RECORD_LEN 40
struct trust_record {
byte rectype;
byte reserved;
union {
- byte raw[TRUST_RECORD_LEN-2];
struct { /* version record: */
byte magic[2];
byte version; /* should be 1 */
byte reserved[3];
u32 locked; /* pid of process which holds a lock */
u32 created; /* timestamp of trustdb creation */
u32 modified; /* timestamp of last modification */
u32 validated; /* timestamp of last validation */
u32 local_id_counter;
byte marginals_needed;
byte completes_needed;
byte max_cert_depth;
} version;
struct { /* public key record */
u32 local_id;
u32 keyid[2];
byte algo;
byte reserved;
byte fingerprint[20];
byte ownertrust;
} pubkey;
struct { /* cache record */
u32 local_id;
u32 keyid[2];
byte valid;
byte reserved;
byte blockhash[20];
byte n_untrusted;
byte n_marginal;
byte n_fully;
byte trustlevel;
} cache;
} r;
};
+typedef struct trust_record TRUSTREC;
+static void create_db( const char *fname );
+static void open_db(void);
+static int read_record( u32 recnum, TRUSTREC *rec );
+static u32 new_local_id(void);
static char *db_name;
+static int db_fd = -1;
+static int no_io_dbg = 0;
+
+#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
+ (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
+#define buftou16( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1)))
+#define u32tobuf( p, a ) do { \
+ ((byte*)p)[0] = a >> 24; \
+ ((byte*)p)[1] = a >> 16; \
+ ((byte*)p)[2] = a >> 8; \
+ ((byte*)p)[3] = a ; \
+ } while(0)
+#define u16tobuf( p, a ) do { \
+ ((byte*)p)[0] = a >> 8; \
+ ((byte*)p)[1] = a ; \
+ } while(0)
+
/**************************************************
************** read and write helpers ************
**************************************************/
static void
fwrite_8(FILE *fp, byte a)
{
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
}
static void
fwrite_16(FILE *fp, u16 a)
{
putc( (a>>8) & 0x0ff , fp );
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing u16 to trustdb: %s\n", strerror(errno) );
}
static int
fwrite_32( FILE*fp, u32 a)
{
putc( (a>>24) & 0xff, fp );
putc( (a>>16) & 0xff, fp );
putc( (a>> 8) & 0xff, fp );
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing u32 to trustdb: %s\n", strerror(errno) );
}
static int
fwrite_zeros( FILE *fp, size_t n)
{
while( n-- )
if( putc( 0, fp ) == EOF )
log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
}
/**************************************************
************** read and write stuff **************
**************************************************/
/****************
* Create a new trustdb
*/
static void
create_db( const char *fname )
{
FILE *fp;
u32 along;
u16 ashort;
fp =fopen( fname, "w" );
if( !fp )
log_fatal("can't create %s: %s\n", fname, strerror(errno) );
fwrite_8( fp, 1 );
fwrite_8( fp, 'g' );
fwrite_8( fp, '1' );
fwrite_8( fp, '0' );
fwrite_8( fp, 1 ); /* version */
fwrite_zeros( fp, 3 ); /* reserved */
fwrite_32( fp, 0 ); /* not locked */
fwrite_32( fp, make_timestamp() ); /* created */
fwrite_32( fp, 0 ); /* not yet modified */
fwrite_32( fp, 0 ); /* not yet validated*/
- fwrite_32( fp, 0 ); /* local-id-counter */
+ fwrite_32( fp, 0 ); /* local-id-counter (not used) */
fwrite_8( fp, 3 ); /* marginals needed */
fwrite_8( fp, 1 ); /* completes needed */
fwrite_8( fp, 4 ); /* max_cet_depth */
fwrite_zeros( fp, 9 ); /* filler */
fclose(fp);
}
+static void
+open_db()
+{
+ TRUSTREC rec;
+ assert( db_fd == -1 );
+
+ db_fd = open( db_name, O_RDWR );
+ if( db_fd == -1 )
+ log_fatal("can't open %s: %s\n", db_name, strerror(errno) );
+ if( read_record( 0, &rec ) )
+ log_fatal("TrustDB %s is invalid\n", db_name );
+ /* fixme: check ->locked and other stuff */
+}
+/****************
+ * read the record with number recnum
+ * returns: -1 on error, 0 on success
+ */
+static int
+read_record( u32 recnum, TRUSTREC *rec )
+{
+ byte buf[TRUST_RECORD_LEN], *p;
+ int rc = 0;
+ int n;
+
+ if( db_fd == -1 )
+ open_db();
+ if( DBG_TRUST && !no_io_dbg )
+ log_debug("trustdb: read_record(%lu)\n", (ulong)recnum);
+ if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
+ log_error("trustdb: lseek failed: %s\n", strerror(errno) );
+ return G10ERR_READ_FILE;
+ }
+ n = read( db_fd, buf, TRUST_RECORD_LEN);
+ if( !n ) {
+ if( DBG_TRUST )
+ log_debug("trustdb: no record at %lu\n", (ulong)recnum );
+ return -1; /* eof */
+ }
+ else if( n != TRUST_RECORD_LEN ) {
+ log_error("trustdb: read failed (n=%d): %s\n", n, strerror(errno) );
+ return G10ERR_READ_FILE;
+ }
+ p = buf;
+ rec->rectype = *p++;
+ rec->reserved = *p++;
+ switch( rec->rectype ) {
+ case 0: /* unused record */
+ break;
+ case 1: /* version record */
+ rec->r.version.magic[0] = *p++;
+ rec->r.version.magic[1] = *p++;
+ rec->r.version.version = *p++;
+ memcpy( rec->r.version.reserved, p, 3); p += 3;
+ rec->r.version.locked = buftou32(p); p += 4;
+ rec->r.version.created = buftou32(p); p += 4;
+ rec->r.version.modified = buftou32(p); p += 4;
+ rec->r.version.validated= buftou32(p); p += 4;
+ rec->r.version.local_id_counter = buftou32(p); p += 4;
+ rec->r.version.marginals_needed = *p++;
+ rec->r.version.completes_needed = *p++;
+ rec->r.version.max_cert_depth = *p++;
+ if( recnum ) {
+ log_error("%s: version record with recnum %lu\n",
+ db_name, (ulong)recnum );
+ rc = G10ERR_TRUSTDB;
+ }
+ if( rec->reserved != 'g' || rec->r.version.magic[0] != '1'
+ || rec->r.version.magic[1] != '0' ) {
+ log_error("%s: not a trustdb file\n", db_name );
+ rc = G10ERR_TRUSTDB;
+ }
+ if( rec->r.version.version != 1 ) {
+ log_error("%s: invalid file version %d\n",
+ db_name, rec->r.version.version );
+ rc = G10ERR_TRUSTDB;
+ }
+ break;
+ case 2:
+ rec->r.pubkey.local_id = buftou32(p); p += 4;
+ rec->r.pubkey.keyid[0] = buftou32(p); p += 4;
+ rec->r.pubkey.keyid[1] = buftou32(p); p += 4;
+ rec->r.pubkey.algo = *p++;
+ rec->r.pubkey.reserved = *p++;
+ memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20;
+ rec->r.pubkey.ownertrust = *p++;
+ if( rec->r.pubkey.local_id != recnum ) {
+ log_error("%s: pubkey local_id != recnum (%lu,%lu)\n",
+ db_name,
+ (ulong)rec->r.pubkey.local_id,
+ (ulong)recnum );
+ rc = G10ERR_TRUSTDB;
+ }
+ break;
+ case 3:
+ rec->r.cache.local_id = buftou32(p); p += 4;
+ rec->r.cache.keyid[0] = buftou32(p); p += 4;
+ rec->r.cache.keyid[1] = buftou32(p); p += 4;
+ rec->r.cache.valid = *p++;
+ rec->r.cache.reserved = *p++;
+ memcpy(rec->r.cache.blockhash, p, 20); p += 20;
+ rec->r.cache.n_untrusted = *p++;
+ rec->r.cache.n_marginal = *p++;
+ rec->r.cache.n_fully = *p++;
+ rec->r.cache.trustlevel = *p++;
+ break;
+ default:
+ log_error("%s: invalid record type %d at recnum %lu\n",
+ db_name, rec->rectype, (ulong)recnum );
+ rc = G10ERR_TRUSTDB;
+ break;
+ }
+ return rc;
+}
+/****************
+ * Write the record at RECNUM
+ */
+static int
+write_record( u32 recnum, TRUSTREC *rec )
+{
+ byte buf[TRUST_RECORD_LEN], *p;
+ int rc = 0;
+ int n;
+
+ if( db_fd == -1 )
+ open_db();
+
+ if( DBG_TRUST && !no_io_dbg )
+ log_debug("trustdb: write_record(%lu)\n", (ulong)recnum);
+ memset(buf, 0, TRUST_RECORD_LEN);
+ p = buf;
+ *p++ = rec->rectype;
+ *p++ = rec->reserved;
+ switch( rec->rectype ) {
+ case 0: /* unused record */
+ break;
+ case 1: /* version record */
+ log_bug(NULL);
+ break;
+ case 2:
+ u32tobuf(p, rec->r.pubkey.local_id); p += 4;
+ u32tobuf(p, rec->r.pubkey.keyid[0]); p += 4;
+ u32tobuf(p, rec->r.pubkey.keyid[1]); p += 4;
+ *p++ = rec->r.pubkey.algo;
+ *p++ = rec->r.pubkey.reserved;
+ memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20;
+ *p++ = rec->r.pubkey.ownertrust;
+ assert( rec->r.pubkey.local_id == recnum );
+ break;
+ case 3:
+ u32tobuf(p, rec->r.cache.local_id); p += 4;
+ u32tobuf(p, rec->r.cache.keyid[0]); p += 4;
+ u32tobuf(p, rec->r.cache.keyid[1]); p += 4;
+ *p++ = rec->r.cache.valid;
+ *p++ = rec->r.cache.reserved;
+ memcpy(p, rec->r.cache.blockhash, 20); p += 20;
+ *p++ = rec->r.cache.n_untrusted;
+ *p++ = rec->r.cache.n_marginal;
+ *p++ = rec->r.cache.n_fully;
+ *p++ = rec->r.cache.trustlevel;
+ break;
+ default:
+ log_bug(NULL);
+ }
+ if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
+ log_error("trustdb: lseek failed: %s\n", strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ n = write( db_fd, buf, TRUST_RECORD_LEN);
+ if( n != TRUST_RECORD_LEN ) {
+ log_error("trustdb: write failed (n=%d): %s\n", n, strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ return rc;
+}
+static u32
+new_local_id()
+{
+ off_t offset;
+ u32 recnum;
+
+ /* fixme: look for unused records */
+ offset = lseek( db_fd, 0, SEEK_END );
+ if( offset == -1 )
+ log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
+ recnum = offset / TRUST_RECORD_LEN;
+ assert(recnum); /* this is will never be the first record */
+ return recnum ;
+}
+
+/****************
+ * Scan the trustdb for a record of type RECTYPE which maches PKC
+ * The local_id is set to the correct value
+ */
+static int
+scan_record( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
+{
+ u32 recnum;
+ u32 keyid[2];
+ byte *fingerprint;
+ size_t fingerlen;
+ int dbg = DBG_TRUST;
+ int rc;
+
+ assert( rectype == 2 || rectype == 3 );
+
+ if( DBG_TRUST )
+ log_debug("trustdb: scan_record\n");
+ keyid_from_pkc( pkc, keyid );
+ fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
+ assert( fingerlen == 20 || fingerlen == 16 );
+
+ no_io_dbg = 1;
+ for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
+ if( rec->rectype != rectype )
+ continue;
+ if( rec->rectype == 2 ) {
+ if( rec->r.pubkey.keyid[0] == keyid[0]
+ && rec->r.pubkey.keyid[1] == keyid[1]
+ && rec->r.pubkey.algo == pkc->pubkey_algo
+ && !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen)
+ ) { /* found */
+ /* store the local_id */
+ if( pkc->local_id && pkc->local_id != recnum )
+ log_error("%s: found record, but local_id from mem does "
+ "not match recnum (%lu,%lu)\n", db_name,
+ (ulong)pkc->local_id, (ulong)recnum );
+ pkc->local_id = recnum;
+ no_io_dbg = 0;
+ return 0;
+ }
+ }
+ else
+ log_bug("not yet implemented\n");
+ }
+ no_io_dbg = 0;
+ if( DBG_TRUST )
+ log_debug("trustdb: scan_record: eof or error\n");
+ if( rc != -1 )
+ log_error("%s: scan_record failed: %s\n",db_name, g10_errstr(rc) );
+ return rc;
+}
/***********************************************
************* trust logic *******************
***********************************************/
+/****************
+ * Verify, that all our public keys are in the trustDB and marked as
+ * ultimately trusted.
+ */
+static int
+verify_own_certs()
+{
+ int rc;
+ void *enum_context = NULL;
+ PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
+ PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+ u32 keyid[2];
+ int trust;
+
+ while( !(rc=enum_secret_keys( &enum_context, skc) ) ) {
+ /* fixme: to be sure that it is a secret key of our own,
+ * we should check it, but this needs a passphrase
+ * for every key and this boring for the user.
+ * Solution: Sign the secring and the trustring
+ * and verify this signature during
+ * startup
+ */
+
+ keyid_from_skc( skc, keyid );
+
+ if( DBG_TRUST )
+ log_debug("checking secret key %08lX\n", (ulong)keyid[1] );
+
+ /* look wether we can access the public key of this secret key */
+ rc = get_pubkey( pkc, keyid );
+ if( rc ) {
+ log_error("keyid %08lX: secret key without public key\n",
+ (ulong)keyid[1] );
+ goto leave;
+ }
+ if( cmp_public_secret_cert( pkc, skc ) ) {
+ log_error("keyid %08lX: secret and public key don't match\n",
+ (ulong)keyid[1] );
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+ /* look into the trustdb */
+ rc = check_pkc_trust( pkc, &trust );
+ if( rc ) {
+ log_info("keyid %08lX: problem in trustdb: %s\n", (ulong)keyid[1],
+ g10_errstr(rc) );
+ goto leave;
+ }
+ if( trust & TRUST_NO_PUBKEY ) {
+ log_info("keyid %08lX: not yet in trustdb\n", (ulong)keyid[1] );
+ /* FIXME: insert */
+ }
+ else if( (trust & TRUST_MASK) != TRUST_ULT_TRUST ) {
+ log_error("keyid %08lX: not marked as ultimately trusted\n",
+ (ulong)keyid[1] );
+ /* FIXME: mark */
+ }
+
+ release_secret_cert_parts( skc );
+ release_public_cert_parts( pkc );
+ }
+ if( rc != -1 )
+ log_error("enum_secret_keys failed: %s\n", g10_errstr(rc) );
+ else
+ rc = 0;
+
+ leave:
+ free_secret_cert( skc );
+ free_public_cert( pkc );
+ return rc;
+}
+
+/****************
+ * Check all the sigs of the given keyblock and mark them
+ * as checked.
+ */
+static int
+check_sigs( KBNODE keyblock )
+{
+ KBNODE kbctx;
+ KBNODE node;
+ int rc;
+
+ for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
+ if( node->pkt->pkttype == PKT_SIGNATURE
+ && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
+ PKT_signature *sig = node->pkt->pkt.signature;
+
+ rc = check_key_signature( keyblock, node );
+ if( !rc )
+ node->flag |= 1; /* mark signature valid */
+ if( DBG_TRUST )
+ log_debug("trustdb: sig from %08lX: %s\n",
+ rc? g10_errstr(rc): "okay" );
+ }
+ }
+ return 0;
+}
+
+
+/****************
+ * Recursive check the signatures.
+ */
+static int
+walk( KBNODE keyblock, int levels )
+{
+ KBNODE kbctx, node;
+
+ check_sigs( keyblock );
+ if( levels ) { /* check the next level */
+ for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
+ if( node->pkt->pkttype == PKT_SIGNATURE && (node->flag & 1) ) {
+ /* read the keyblock for this signator */
+
+ /* and check his signatures */
+ /*walk( his_keyblock, levels-1)*/
+ }
+ }
+ }
+
+}
+
+
+
+
+
+/****************
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+static int
+check_trust()
+{
+}
+
/*********************************************************
**************** API Interface ************************
*********************************************************/
/****************
* Perform some checks over the trustdb
- * level 0: used on initial program startup
+ * level 0: used for initial program startup
*/
int
check_trustdb( int level )
{
+ int rc=0;
+
if( !level ) {
char *fname = make_filename("~/.g10", "trustDB", NULL );
if( access( fname, R_OK ) ) {
if( errno != ENOENT ) {
log_error("can't access %s: %s\n", fname, strerror(errno) );
m_free(fname);
return G10ERR_TRUSTDB;
}
create_db( fname );
}
m_free(db_name);
db_name = fname;
/* we can verify a signature about our local data (secring and trustdb)
- * in ~/.g10/ here
- */
+ * in ~/.g10/ here */
+ rc = verify_private_data();
+ if( !rc ) {
+ /* verify, that our own certificates are in the trustDB
+ * or move them to the trustdb. */
+ rc = verify_own_certs();
+
+ /* should we check wether there is no other ultimately trusted
+ * key in the database? */
+
+ }
}
else
log_bug(NULL);
- return 0;
+ return rc;
}
/****************
* Get the trustlevel for this PKC.
* Note: This does not ask any questions
* Returns: 0 okay of an errorcode
*
* It operates this way:
* locate the pkc in the trustdb
* found:
* Do we have a valid cache record for it?
* yes: return trustlevel from cache
* no: make a cache record
* not found:
* Return with a trustlevel, saying that we do not have
* a trust record for it. The caller may use insert_trust_record()
* and then call this function here again.
*
* Problems: How do we get the complete keyblock to check that the
* cache record is actually valid? Think we need a clever
* cache in getkey.c to keep track of this stuff. Maybe it
* is not necessary to check this if we use a local pubring. Hmmmm.
*/
int
check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel )
{
+ TRUSTREC rec;
int trustlevel = 0;
+ int rc=0;
if( opt.verbose )
log_info("check_pkc_trust() called.\n");
+ /* get the pubkey record */
+ if( pkc->local_id ) {
+ if( read_record( pkc->local_id, &rec ) ) {
+ log_error("check_pkc_trust: read record failed\n");
+ return G10ERR_TRUSTDB;
+ }
+ }
+ else { /* no local_id: scan the trustdb */
+ if( (rc=scan_record( pkc, &rec, 2 )) && rc != -1 ) {
+ log_error("check_pkc_trust: scan_record(2) failed: %s\n",
+ g10_errstr(rc));
+ return G10ERR_TRUSTDB;
+ }
+ else if( rc == -1 ) {
+ log_error("check_pkc_trust: pubkey not in TrustDB\n");
+ trustlevel = TRUST_NO_PUBKEY;
+ goto leave;
+ }
+ }
+ /* fixme: do some additional checks on the pubkey record */
+
+
+ leave:
+ if( opt.verbose )
+ log_info("check_pkc_trust() returns trustlevel %04x.\n", trustlevel);
*r_trustlevel = trustlevel;
return 0;
}
+
+/****************
+ * Insert a trust record into the TrustDB
+ * This function failes if this record already exists.
+ */
+int
+insert_trust_record( PKT_public_cert *pkc )
+{
+ TRUSTREC rec;
+ u32 keyid[2];
+ u32 recnum;
+ byte *fingerprint;
+ size_t fingerlen;
+
+
+ if( DBG_TRUST )
+ log_debug("trustdb: insert_record\n");
+
+ assert( !pkc->local_id );
+
+ keyid_from_pkc( pkc, keyid );
+ fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
+
+ /* FIXME: check that we do not have this record. */
+
+ recnum = new_local_id();
+ /* build record */
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = 2; /* the pubkey record */
+ rec.r.pubkey.local_id = recnum;
+ rec.r.pubkey.keyid[0] = keyid[0];
+ rec.r.pubkey.keyid[1] = keyid[1];
+ rec.r.pubkey.algo = pkc->pubkey_algo;
+ memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
+ rec.r.pubkey.ownertrust = 0;
+ if( write_record( recnum, &rec ) ) {
+ log_error("insert_trust_record: write failed\n");
+ return G10ERR_TRUSTDB;
+ }
+
+ pkc->local_id = recnum;
+
+ return 0;
+}
+
+
+int
+update_trust_record( PKT_public_cert *pkc, int new_trust )
+{
+ TRUSTREC rec;
+ u32 keyid[2];
+ u32 recnum;
+
+ if( DBG_TRUST )
+ log_debug("trustdb: update_record\n");
+
+ assert( pkc->local_id );
+
+ if( read_record( pkc->local_id, &rec ) ) {
+ log_error("update_trust_record: read failed\n");
+ return G10ERR_TRUSTDB;
+ }
+ /* check keyid, fingerprint etc ? */
+
+ recnum = new_local_id();
+ /* build record */
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = 2; /* the pubkey record */
+ rec.r.pubkey.local_id = recnum;
+ rec.r.pubkey.keyid[0] = keyid[0];
+ rec.r.pubkey.keyid[1] = keyid[1];
+ rec.r.pubkey.algo = pkc->pubkey_algo;
+ memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
+ rec.r.pubkey.ownertrust = 0;
+ if( write_record( recnum, &rec ) ) {
+ log_error("insert_trust_record: write failed\n");
+ return G10ERR_TRUSTDB;
+ }
+
+ pkc->local_id = recnum;
+
+ return 0;
+}
+
+
+int
+verify_private_data()
+{
+ int rc = 0;
+ char *sigfile = make_filename("~/.g10", "sig", NULL );
+
+ if( access( sigfile, R_OK ) ) {
+ if( errno != ENOENT ) {
+ log_error("can't access %s: %s\n", sigfile, strerror(errno) );
+ rc = G10ERR_TRUSTDB;
+ goto leave;
+ }
+ log_info("private data signature missing; creating ...\n");
+ rc = sign_private_data();
+ if( rc ) {
+ log_error("error creating %s: %s\n", sigfile, g10_errstr(rc) );
+ goto leave;
+ }
+ }
+
+ /* FIXME: verify this signature */
+
+ leave:
+ m_free(sigfile);
+ return rc;
+}
+
+
+int
+sign_private_data()
+{
+ int rc;
+ char *sigfile = make_filename("~/.g10", "sig", NULL );
+ char *secring = make_filename("~/.g10", "secring.g10", NULL );
+ STRLIST list = NULL;
+
+ add_to_strlist( &list, db_name );
+ add_to_strlist( &list, secring );
+
+ rc = sign_file( list, 1, NULL, 0, NULL, sigfile);
+
+ m_free(sigfile);
+ m_free(secring);
+ free_strlist(list);
+ return rc;
+}
+
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 01f126808..aff668e84 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -1,28 +1,42 @@
/* trustdb.h - Trust database
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_TRUSTDB_H
#define G10_TRUSTDB_H
+
+
+#define TRUST_MASK 0x07 /* for the trust leveles */
+#define TRUST_UNKNOWN 1 /* unknown */
+#define TRUST_NO_TRUST 2 /* not trusted */
+#define TRUST_MARG_TRUST 4 /* marginally trusted */
+#define TRUST_FULL_TRUST 5 /* fully trusted */
+#define TRUST_ULT_TRUST 7 /* ultimately trusted */
+ /* other bits used with the trustlevel */
+#define TRUST_NO_PUBKEY 0x10 /* we do not have the pubkey in out trustDB */
+
+
/*-- trustdb.c --*/
int check_trustdb( int level );
int check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel );
+int verify_private_data(void);
+int sign_private_data(void);
#endif /*G10_TRUSTDB_H*/
diff --git a/include/util.h b/include/util.h
index 34015ffe6..7f2593022 100644
--- a/include/util.h
+++ b/include/util.h
@@ -1,115 +1,116 @@
/* util.h
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_UTIL_H
#define G10_UTIL_H
#include "types.h"
#include "errors.h"
#include "types.h"
#include "mpi.h"
typedef struct {
int *argc; /* pointer to argc (value subject to change) */
char ***argv; /* pointer to argv (value subject to change) */
unsigned flags; /* Global flags (DO NOT CHANGE) */
int err; /* print error about last option */
/* 1 = warning, 2 = abort */
int r_opt; /* return option */
int r_type; /* type of return value (0 = no argument found)*/
union {
int ret_int;
long ret_long;
ulong ret_ulong;
char *ret_str;
} r; /* Return values */
struct {
int index;
int inarg;
int stopped;
const char *last;
} internal; /* DO NOT CHANGE */
} ARGPARSE_ARGS;
typedef struct {
int short_opt;
const char *long_opt;
unsigned flags;
const char *description; /* optional option description */
} ARGPARSE_OPTS;
/*-- logger.c --*/
void log_set_pid( int pid );
int log_get_errorcount( int clear );
void printstr( int level, const char *fmt, ... );
void log_bug( const char *fmt, ... );
void log_fatal( const char *fmt, ... );
void log_error( const char *fmt, ... );
void log_info( const char *fmt, ... );
void log_debug( const char *fmt, ... );
void log_hexdump( const char *text, char *buf, size_t len );
void log_mpidump( const char *text, MPI a );
/*-- errors.c --*/
const char * g10_errstr( int no );
/*-- argparse.c --*/
int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
void usage( int level );
const char *default_strusage( int level );
/*-- (main program) --*/
const char *strusage( int level );
/*-- fileutil.c --*/
char *make_filename( const char *first_part, ... );
/*-- miscutil.c --*/
u32 make_timestamp(void);
void print_string( FILE *fp, byte *p, size_t n );
int answer_is_yes( const char *s );
/*-- strgutil.c --*/
void free_strlist( STRLIST sl );
#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+void add_to_strlist( STRLIST *list, const char *string );
char *memistr( char *buf, size_t buflen, const char *sub );
char *trim_spaces( char *string );
int string_count_chr( const char *string, int c );
#define stricmp(a,b) strcasecmp((a),(b))
#ifndef HAVE_STPCPY
char *stpcpy(char *a,const char *b);
#endif
#ifndef HAVE_STRLWR
char *strlwr(char *a);
#endif
/******** some macros ************/
#ifndef STR
#define STR(v) #v
#endif
#define STR2(v) STR(v)
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member)
#endif /*G10_UTIL_H*/
diff --git a/util/strgutil.c b/util/strgutil.c
index ecdcb750c..cb80c57ab 100644
--- a/util/strgutil.c
+++ b/util/strgutil.c
@@ -1,128 +1,140 @@
/* strgutil.c - miscellaneous utilities
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <ctype.h>
#include "types.h"
#include "util.h"
#include "memory.h"
void
free_strlist( STRLIST sl )
{
STRLIST sl2;
for(; sl; sl = sl2 ) {
sl2 = sl->next;
m_free(sl);
}
}
+
+void
+add_to_strlist( STRLIST *list, const char *string )
+{
+ STRLIST sl;
+
+ sl = m_alloc( sizeof *sl + strlen(string));
+ strcpy(sl->d, string);
+ sl->next = *list;
+ *list = sl;
+}
+
/****************
* look for the substring SUB in buffer and return a pointer to that
* substring in BUF or NULL if not found.
* Comparison is case-in-sensitive.
*/
char *
memistr( char *buf, size_t buflen, const char *sub )
{
const byte *t, *s ;
size_t n;
for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
if( toupper(*t) == toupper(*s) ) {
for( buf=(char*)t++, buflen = n--, s++;
n && toupper(*t) == toupper(*s); t++, s++, n-- )
;
if( !*s )
return buf;
t = buf; n = buflen; s = sub ;
}
return NULL ;
}
/****************
* remove leading and trailing white spaces
*/
char *
trim_spaces( char *str )
{
char *string, *p, *mark;
string = str;
/* find first non space character */
for( p=string; *p && isspace( *(byte*)p ) ; p++ )
;
/* move characters */
for( (mark = NULL); (*string = *p); string++, p++ )
if( isspace( *(byte*)p ) ) {
if( !mark )
mark = string ;
}
else
mark = NULL ;
if( mark )
*mark = '\0' ; /* remove trailing spaces */
return str ;
}
int
string_count_chr( const char *string, int c )
{
int count;
for(count=0; *string; string++ )
if( *string == c )
count++;
return count;
}
/*********************************************
********** missing string functions *********
*********************************************/
#ifndef HAVE_STPCPY
char *
stpcpy(char *a,const char *b)
{
while( *b )
*a++ = *b++;
*a = 0;
return (char*)a;
}
#endif
#ifndef HAVE_STRLWR
char *
strlwr(char *s)
{
char *p;
for(p=s; *p; p++ )
*p = tolower(*p);
return s;
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, May 10, 9:09 AM (21 h, 49 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a3/cf/cebc949d35fbc492ff69b9aabf24
Attached To
rG GnuPG
Event Timeline
Log In to Comment