File: subprocess_sign.c

package info (click to toggle)
tinyssh 20250501-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,388 kB
  • sloc: ansic: 20,245; sh: 1,582; python: 1,449; makefile: 913
file content (95 lines) | stat: -rw-r--r-- 2,818 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
86
87
88
89
90
91
92
93
94
95
/*
20140117
20241208 - reformated using clang-format
Jan Mojzis
Public domain.
*/

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "load.h"
#include "log.h"
#include "open.h"
#include "writeall.h"
#include "purge.h"
#include "global.h"
#include "bug.h"
#include "e.h"
#include "purge.h"
#include "readall.h"
#include "blocking.h"
#include "sshcrypto.h"
#include "subprocess.h"

/*
The 'subprocess_sign' function reads secret-key from 'keydir' and signs the data
'x' of length 'xlen' and returns it in 'y'. Caller is expecting 'y' of length
'ylen'. Signing is done in a different process, so secret-key is in a separate
memory space than rest of the program.
*/
int subprocess_sign(unsigned char *y, long long ylen, const char *keydir,
                    unsigned char *x, long long xlen) {

    pid_t pid;
    int status, fromchild[2] = {-1, -1};

    if (ylen != sshcrypto_sign_bytes) bug_inval();
    if (xlen != sshcrypto_hash_bytes) bug_inval();
    if (!y || !keydir || !x) bug_inval();

    if (open_pipe(fromchild) == -1) return -1;
    pid = fork();
    if (pid == -1) {
        close(fromchild[0]);
        close(fromchild[1]);
        return -1;
    }
    if (pid == 0) {
        unsigned char sk[sshcrypto_sign_SECRETKEYMAX];
        unsigned char sm[sshcrypto_sign_MAX + sshcrypto_hash_MAX];
        unsigned long long smlen;

        close(fromchild[0]);

        /* signing starts here */
        if (chdir(keydir) == -1) {
            log_w2("sign: unable to change directory to ", keydir);
            global_die(111);
        }
        if (load(sshcrypto_sign_secretkeyfilename, sk,
                 sshcrypto_sign_secretkeybytes) == -1) {
            log_w4("sign: unable to load secret-key from file ", keydir, "/",
                   sshcrypto_sign_secretkeyfilename);
            purge(sk, sizeof sk);
            global_die(111);
        }
        if (sshcrypto_sign(sm, &smlen, x, sshcrypto_hash_bytes, sk) != 0) {
            log_w4("sign: unable to sign using secret-key from file ", keydir,
                   "/", sshcrypto_sign_secretkeyfilename);
            purge(sk, sizeof sk);
            global_die(111);
        }
        purge(sk, sizeof sk);
        if (writeall(fromchild[1], sm, sshcrypto_sign_bytes) == -1) {
            log_w1("sign: unable to write signature to parrent process");
            global_die(111);
        }
        close(fromchild[1]);
        /* signing ends here */

        purge(sm, sizeof sm);
        global_die(0);
    }
    close(fromchild[1]);
    blocking_enable(fromchild[0]);
    if (readall(fromchild[0], y, ylen) == -1) {
        close(fromchild[0]);
        return -1;
    }
    close(fromchild[0]);

    while (waitpid(pid, &status, 0) != pid) {}
    if (!WIFEXITED(status)) return -1;
    return WEXITSTATUS(status);
}