lsh-decode-key.c 4.39 KB
Newer Older
1
2
3
4
5
6
/* lsh-decode-key.c
 *
 * Decode ssh2 keys.
 *
 */

7
8
9
10
11
12
13
14
15
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <fcntl.h>
#include <unistd.h>

#include "nettle/sexp.h"

16
#include "crypto.h"
Niels Möller's avatar
Niels Möller committed
17
#include "format.h"
18
19
#include "io.h"
#include "lsh_argp.h"
20
#include "lsh_string.h"
Niels Möller's avatar
Niels Möller committed
21
#include "parse.h"
22
#include "spki.h"
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "version.h"
#include "werror.h"
#include "xalloc.h"

#include "lsh-decode-key.c.x"

/* Option parsing */

const char *argp_program_version
= "lsh-decode-key-" VERSION;

const char *argp_program_bug_address = BUG_ADDRESS;

/* GABA:
   (class
     (name lsh_decode_key_options)
39
     (super werror_config)
40
41
     (vars
       ; Output filename
Niels Möller's avatar
Niels Möller committed
42
       (file string)
43
44

       ; Assume input is base64
Niels Möller's avatar
Niels Möller committed
45
       (base64 . int)))
46
47
48
49
50
51
*/

static struct lsh_decode_key_options *
make_lsh_decode_key_options(void)
{
  NEW(lsh_decode_key_options, self);
52
53
  init_werror_config(&self->super);

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  self->file = NULL;
  self->base64 = 0;

  return self;
}

static const struct argp_option
main_options[] =
{
  /* Name, key, arg-name, flags, doc, group */
  { "output-file", 'o', "Filename", 0, "Default is stdout", 0 },
  { "base64", 'b', NULL, 0, "Input is base64 encoded", 0 },
  { NULL, 0, NULL, 0, NULL, 0 }
};

static const struct argp_child
main_argp_children[] =
{
  { &werror_argp, 0, "", 0 },
  { NULL, 0, NULL, 0}
};

static error_t
main_argp_parser(int key, char *arg, struct argp_state *state)
{
  CAST(lsh_decode_key_options, self, state->input);

  switch(key)
    {
    default:
      return ARGP_ERR_UNKNOWN;

86
87
88
89
    case ARGP_KEY_INIT:
      state->child_inputs[0] = &self->super;
      break;
      
90
    case ARGP_KEY_END:
91
92
      if (!werror_init(&self->super))
	argp_failure(state, EXIT_FAILURE, errno, "Failed to open log file");
93
94
95
96
97
98
99
      break;
      
    case 'b':
      self->base64 = 1;
      break;
      
    case 'o':
Niels Möller's avatar
Niels Möller committed
100
      self->file = ssh_format("%lz", arg);
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
      break;
    }
  return 0;
}

static const struct argp
main_argp =
{ main_options, main_argp_parser, 
  NULL,
  ( "Converts a raw OpenSSH/ssh2 public key to sexp-format.\v"
    "Usually invoked by the ssh-conv script."),
  main_argp_children,
  NULL, NULL
};


Niels Möller's avatar
Niels Möller committed
117
static struct lsh_string *
118
lsh_decode_key(struct lsh_string *contents)
119
{
120
  struct simple_buffer buffer;
121
  enum lsh_atom type;
122

123
  simple_buffer_init(&buffer, STRING_LD(contents));
124
125

  if (!parse_atom(&buffer, &type))
126
    {
127
128
      werror("Invalid (binary) input data.\n");
      return NULL;
129
    }
130
131

  switch (type)
132
    {
133
134
135
136
    case ATOM_SSH_DSS:
      {
        struct verifier *v;
        
137
        werror("Reading key of type ssh-dss...\n");
138
139
140
141
142
143
144
145
146

        v = parse_ssh_dss_public(&buffer);
        
        if (!v)
          {
            werror("Invalid dsa key.\n");
            return NULL;
          }
        else
Niels Möller's avatar
Niels Möller committed
147
          return PUBLIC_SPKI_KEY(v, 1);
148
149
150
151
152
153
      }
      
    case ATOM_SSH_RSA:
      {
          struct verifier *v;
          
154
          werror("Reading key of type ssh-rsa...\n");
155
156
157
158
159
160
161
162
163

          v = parse_ssh_rsa_public(&buffer);

          if (!v)
            {
              werror("Invalid rsa key.\n");
              return NULL;
            }
          else
Niels Möller's avatar
Niels Möller committed
164
            return PUBLIC_SPKI_KEY(v, 1);
165
166
167
168
      }      
    default:
      werror("Unknown key type.");
      return NULL;
169
170
171
172
    }
}


173
int main(int argc, char **argv)
174
{
175
176
177
178
179
180
181
  struct lsh_decode_key_options *options = make_lsh_decode_key_options();
  struct lsh_string *input;
  struct lsh_string *output;
  
  int out = STDOUT_FILENO;
  
  argp_parse(&main_argp, argc, argv, 0, NULL, options);
182

183
184
185
186
187
188
  if (options->file)
    {
      out = open(lsh_get_cstring(options->file),
                 O_WRONLY | O_CREAT, 0666);
      if (out < 0)
        {
189
190
          werror("Failed to open file `%S' for writing %e\n",
                 options->file, errno);
191
192
193
          return EXIT_FAILURE;
        }
    }
194

195
196
197
  input = io_read_file_raw(STDIN_FILENO, 3000);
  if (!input)
    {
198
      werror("Failed to read stdin %e\n", errno);
199
200
      return EXIT_FAILURE;
    }
201

202
203
  if (options->base64)
    {
204
      if (!lsh_string_base64_decode(input))
205
	{
206
          werror("Invalid base64 encoding.\n");
207
208
209

	  lsh_string_free(input);

210
211
212
          return EXIT_FAILURE;
        }
    }
213
  
Niels Möller's avatar
Niels Möller committed
214
  output = lsh_decode_key(input);
215
  lsh_string_free(input);
216
217
218
219
220
221
222

  if (!output)
    {
      werror("Invalid ssh2 key.\n");
      return EXIT_FAILURE;
    }
    
223
  if (!write_raw(out, STRING_LD(output)))
224
    {
225
      werror("Write failed: %e\n", errno);
226
227
      return EXIT_FAILURE;
    }
228
  lsh_string_free(output);
229
230
  
  gc_final();
231
  
232
233
  return EXIT_SUCCESS;
}