summarylogtreecommitdiffstats
path: root/smartcard_hook
blob: d378a4a20ac799363463525f88e506c08868ed96 (plain)
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
96
97
98
99
100
101
102
103
#!/usr/bin/ash

run_hook() {
    [ "${quiet}" = "y" ] && CSQUIET=">/dev/null"

    if [ -n "$gpgdir" ]; then
        IFS=: read gpgdir_dev gpgdir_fs gpgdir_dirname <<EOF
$gpgdir
EOF

        if [ -n "$cryptkey" ]; then
            echo "Warning: The 'cryptkey' kernel parameter has also been provided."
            echo "The 'cryptkey' parameter will be overwritten by the [smartcard] hook."
        fi
    
        ckeyfile="/crypto_keyfile.bin.gpg"
        ckeyfile_out="/crypto_keyfile.bin"
        dogpgdecryption=0


        # Copy the GPG directory
        if resolved=$(resolve_device "${gpgdir_dev}" ${rootdelay}); then

            # Mount
            mkdir /gpgdrive
            mount -r -t "$gpgdir_fs" "$resolved" /gpgdrive
            
            gpgdir_basepath="/gpgdrive/$gpgdir_dirname"
            if [ -d "$gpgdir_basepath" ]; then
            
                # Copy .gnupg homedirectory
                if [ -d "$gpgdir_basepath/homedir" ]; then
                    mkdir -p "/.gnupg"
                    cp -a -r -T "$gpgdir_basepath/homedir/" "/.gnupg/"
                fi
                
                # Copy keyfile
                if [ -f "$gpgdir_basepath/key.gpg" ]; then
                    dd if="$gpgdir_basepath/key.gpg" of="$ckeyfile" >/dev/null 2>&1
                    dogpgdecryption=1
                else
                    echo "GPG directory found, but it contains no key.gpg"
                fi
              
            else
                echo "Could not access GPG directory."
            fi
                
            umount /gpgdrive
        fi
        
        # Check for encrypted keyfile
        [ ! -f ${ckeyfile} ] && echo "GPG-encrypted Keyfile could not be opened. Reverting to normal keyfile or passphrase." && dogpgdecryption=0
        
        
        # Decrypt keyfile using GPG
        if [ ${dogpgdecryption} -gt 0 ]; then
        
            # Run PCSC daemon
            pcscd &
            
            # Limit the number of tries
            maxtries=2
            tries=0
            success=0
            
            while [ $maxtries -gt $tries ] && [ $success -ne 1 ]; do
                tries=$((tries+1))
            
                echo "Enter PIN or passphrase for GPG decryption:"
                read -s pincode
                
                # todo: run gpg --card-status
                # That imports the private key stubs from the card.
                # However, it doesn't create the public keys and thus the decryption will not work
                # without public keys being available seperately.
                
                if eval printf '%s' "$pincode" | gpg --batch --passphrase-fd 0 --pinentry-mode loopback --homedir "/.gnupg" --output ${ckeyfile_out} --decrypt ${ckeyfile} ${CSQUIET}; then
                    
                    success=1
                    # Set cryptkey for encrypt hook
                    cryptkey="rootfs:${ckeyfile_out}:"
                else
                    echo "GPG decryption failed! Wrong PIN? Smart card device inserted?"
                fi
            done
            
            
            if [ $success -ne 1 ]; then
                echo "Aborting GPG decryption!"
            fi
            
            # for now: kill gpg-agent and pcscd so that the smart card can be used by the normal user. In that case, the PIN has to be entered again.
            # todo: maybe somehow pass the GPG agent session on to the user
            killall gpg-agent
            killall pcscd
        fi
        
        
    else
        echo "No GPG-encrypted keyfile provided."
    fi
}