001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package sop.cli.picocli.commands; 006 007import java.io.File; 008import java.io.FileInputStream; 009import java.io.FileNotFoundException; 010import java.io.IOException; 011import java.util.ArrayList; 012import java.util.List; 013 014import picocli.CommandLine; 015import sop.Ready; 016import sop.cli.picocli.Print; 017import sop.cli.picocli.SopCLI; 018import sop.enums.SignAs; 019import sop.exception.SOPGPException; 020import sop.operation.Sign; 021 022@CommandLine.Command(name = "sign", 023 description = "Create a detached signature on the data from standard input", 024 exitCodeOnInvalidInput = 37) 025public class SignCmd implements Runnable { 026 027 @CommandLine.Option(names = "--no-armor", 028 description = "ASCII armor the output", 029 negatable = true) 030 boolean armor = true; 031 032 @CommandLine.Option(names = "--as", description = "Defaults to 'binary'. If '--as=text' and the input data is not valid UTF-8, sign fails with return code 53.", 033 paramLabel = "{binary|text}") 034 SignAs type; 035 036 @CommandLine.Parameters(description = "Secret keys used for signing", 037 paramLabel = "KEY") 038 List<File> secretKeyFile = new ArrayList<>(); 039 040 @Override 041 public void run() { 042 Sign sign = SopCLI.getSop().sign(); 043 044 if (type != null) { 045 try { 046 sign.mode(type); 047 } catch (SOPGPException.UnsupportedOption unsupportedOption) { 048 Print.errln("Unsupported option '--as'"); 049 Print.trace(unsupportedOption); 050 System.exit(unsupportedOption.getExitCode()); 051 } 052 } 053 054 if (secretKeyFile.isEmpty()) { 055 Print.errln("Missing required parameter 'KEY'."); 056 System.exit(19); 057 } 058 059 for (File keyFile : secretKeyFile) { 060 try (FileInputStream keyIn = new FileInputStream(keyFile)) { 061 sign.key(keyIn); 062 } catch (FileNotFoundException e) { 063 Print.errln("File " + keyFile.getAbsolutePath() + " does not exist."); 064 Print.trace(e); 065 System.exit(1); 066 } catch (IOException e) { 067 Print.errln("Cannot access file " + keyFile.getAbsolutePath()); 068 Print.trace(e); 069 System.exit(1); 070 } catch (SOPGPException.KeyIsProtected e) { 071 Print.errln("Key " + keyFile.getName() + " is password protected."); 072 Print.trace(e); 073 System.exit(1); 074 } catch (SOPGPException.BadData badData) { 075 Print.errln("Bad data in key file " + keyFile.getAbsolutePath() + ":"); 076 Print.trace(badData); 077 System.exit(badData.getExitCode()); 078 } 079 } 080 081 if (!armor) { 082 sign.noArmor(); 083 } 084 085 try { 086 Ready ready = sign.data(System.in); 087 ready.writeTo(System.out); 088 } catch (IOException e) { 089 Print.errln("IO Error."); 090 Print.trace(e); 091 System.exit(1); 092 } catch (SOPGPException.ExpectedText expectedText) { 093 Print.errln("Expected text input, but got binary data."); 094 Print.trace(expectedText); 095 System.exit(expectedText.getExitCode()); 096 } 097 } 098}