Writing panel manager for certificate keystore in Linux Shell
Tags: linux, bash, devops, programming
Published: 2021-03-24 22:41:44


Hi all! My name is Sergii, and I work as a software engineer/DevOps at Luxoft.

Many developers underestimate or incorrectly refer to Linux Shell by comparing it to other programming languages.

But we must not forget that the most important thing in “Linux Shell” is the word *shell*. It is not just a programming language for writing programs.

It is an operating system shell written by system engineers for system engineers, and it is powerful and versatile enough to automate and simplify almost all routine operations without the direct use of other programming languages.

It operates not with libraries, but with programs (many GNU tools and everything you can find and write yourself easily integrates with the shell). It also does not follow the standards of a programming language, but the standards of an operating system. Therefore, even a basic knowledge of how an operating system works will improve your knowledge of Linux Shell.

# About certificates.
![Certificates](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mowu4vpujf4ypb20j613.png)
Since HTTPS became the common standard, almost every project has used certificates such as:

* Certificates that everyone can generate themselves
* Those issued by the corporate CA
* Free public certificates from Let’s Encrypt
* Commercial certificates from a world-wide CA like IdenTrust or DigiCert and others that also provide additional services such as company verification or government accreditation
* Certificates for creating a tls/ssl channel, for authorization on a third-party service, or a certificate for creating a two-way tls/ssl

If you have a lot of certificates, most likely you are using keystore such as JKS (Java keystore, which has acquired legacy status with the release of the Java 9) or PKCS12. The latter has been in use for almost 20 years, and despite some amount of criticism, is one of the most popular and reliable open formats to completely overtake JKS in the near future.

I worked a lot in projects where the main programming language was Java, so for myself, the main tool to work with keystores — *keytool*, which comes with JDK.

Of course, I also have a small cheat sheet with commands such as:

Display list of certificates:
```
keytool -list -v -keystore “store.jks” -storepass “password”|grep -P ‘(Alias name:|Entry type:|Serial number:|Owner:|Valid from:)’

# with some filter:
keytool -list -v -keystore Ltest.jks -storepass changeit 2>/dev/null|grep -P “(Alias:|Owner:|Valid from:)”
```

Copy certificate from one keystore to another keystore:
```
keytool -importkeystore -srckeystore “KEYSTORE_FROM.jks” -srcstorepass “SOURCE_PASSWORD” -destkeystore “KEYSTORE_TO.jks” -deststorepass “DESTINATION_PASSWORD” -srcalias “CERT_ALIAS” [ -destalias “NEW_CERT_ALIAS” ]
```

Import certificate from PEM file to keystore:
```
keytool -import -file “FILE_FROM.pem” -keystore “KEYSTORE_TO.jks” -storepass “KEYSTORE_PASSWORD” -noprompt -alias “CERT_ALIAS”
```

Export certificate from keystore to CRT file:
```
keytool -exportcert -v -alias “CERT_ALIAS” -keystore “KEYSTORE_FROM.jks” -storepass “KEYSTORE_PASSWORD” -rfc -file “FILE_TO.cer”`
```

Once, I worked on a project where there were several dozen micro-services, a few hundreds of virtual machines in test environments, where the developers manually managed the certificates and there was no centralized control. Only in order to disassemble all this and bring it into some systemic form, it was necessary to meticulously sort everything out, compare it, confirm all the changes with several dev teams...

As an infrastructure engineer, I didn’t like it very much, but the amount of the initial routine and low priority of this task forced me to go around and give priority to other tasks.

From time to time, I tried to find some magic solution, get acquainted with the graphical utility https://keystore-explorer.org/features.html, but the necessary functionality was not there, and the company’s policy did not allow the use of desktop programs that had not passed a corporate security audit, which could take up to a year.

Maybe I would get myself together and do everything in a week or two with one-line bash commands + notebook + excel, but suddenly I had to take time off due to illness, and when my temperature allowed me to sit at the monitor again, but not yet go to work, I remembered that I consider myself good with bash.

So let me introduce:
# Console two-panel manager written in Linux shell.

~35 kilobytes POSIX compatible Linux Shell.

To work you need:

* not very old shell (ksh, bash, zsh)
* sed, grep
* keytool that comes with the JDK

What the manager can do. Quick overview in the screenshots below:

Single-panel mode:
![Single mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dg41hyzdrbtksdifilg9.png)

Two-panel mode:
![Two-panel mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bvxr1ysfq760egw8hth.png)

For fans of panel managers, such as NC, VC, MC, FAR, etc. (I can’t live without a FAR manager), the function keys and navigation should be intuitive.

## What was the most interesting during the development:

In the beginning, I wrote the first version in bash including basic navigation and the first functionality, but at some point something didn’t start in ksh. I realized my mistake and rewrote everything in favor of POSIX compatibility.

The code began to look more bulky, but the script worked in bash/ksh/dash. If you find any issues, just write in the comments. (It works even in git-bash, but with awful performance).

## Automatic adjustment width and height.

Since screen is completely refreshed with almost every keypress, you can change the size of the window (for example, if you sit through the graphical ssh client) at any time. After pressing any key, it will automatically adjust the picture. A couple of evenings were spent on the option of showing/hiding additional columns. It was necessary to calculate and adjust for single-panel and two-panel mode, plus headings and text are calculated by different formulas. Here’s a snippet to determine how much to trim the certificate alias ​​if the screen width is not enough to fit the full name:
```
    WindowWidth=”$(tput cols)”
    if [ -n “$RFILE” ]; then # two-panel
    used=24
    [ -n “$SHOW_TYPE” ] && used=$(( $used+34 ))
    localWidth=$(( ( $WindowWidth — $used ) / 2–1 ))
    if [ $localWidth -ne $aliasWidth ]; then
    aliasWidth=$localWidth
    [ $aliasWidth -lt 1 ] && aliasWidth=1
    clear
    fi

    ……………………………………………………………

    headerWidth=$(( $aliasWidth + 5 ))
    [ -n “$SHOW_TYPE” ] && headerWidth=$(( $headerWidth + 17 ))
    printf “ store: ${blue}%-$(( $headerWidth ))s${rst}” “$LFILE”
    printf “| store: ${blue}%-$(( $headerWidth -1 ))s${rst}\n” “$RFILE”
    printf “ %-10s” “Valid to”
    [ -n “$SHOW_TYPE” ] && printf “ %-16s” “Storetype”
    printf “ %-${aliasWidth}s |” “Alias”
    printf “ %-10s” “Valid to”
    [ -n “$SHOW_TYPE” ] && printf “ %-16s” “Storetype”
    printf “ %-${aliasWidth}s\n” “Alias”
```
## Detect of non-printable keys (arrows, F1…):

Some special keys can have variable amounts of characters, so just using a single *read* command was not enough. But, after some experimenting and googling, I found that the read command understands what a millisecond is. So the procedure looks like:
```
    # Special keypress could take variable amount of characters
    keypress=””
    read -rsN1 keytap
    while [ -n “$keytap” ]; do
    keypress=”${keypress}${keytap}”
    read -sN1 -t 0.01 keytap
    done
```
Now You can compare the $keypress value ​​with strings such as ‘[A’ (hex:1B 5B 41) — the up arrow, ‘[B’ (hex: 1B 5B 42) — the down arrow, ‘[13~’ (hex:1B 5B 31 33 7E) — the F3 key, and so on. I’m not quite sure that my version will work perfectly in every shell, so, just in case, most hotkeys are duplicated with letters.

## Some points I want to share
At the moment, all the most important functions I am often using are implemented and I took a break, in addition actually I started writing the script just to get some practice with *tput* and navigation in bash, but I was fascinated a bit ;)

In a simplified form, I already use similar navigation in my other scripts — in some cases it is much more convenient than the standard *select* command due to the ability to make hotkeys and display customized lists.

A very important moment, I believe, is that jks_mgr.sh is just a single text script file.

No obfuscation, open code, also the code is as simple as possible — almost any junior developer/system administrator can check for the absence of back-doors.

So if you are working on a project where each program needs to pass security audit, license verification, or on the target machine, there are simply not enough rights to install tools — this script can be very useful for you. It does not need to be installed, it requires only the POSIX shell, keytool, sed and grep commands to run.

Some regret: the habit of working with Java forced me to do all the work with keystores through the keytool command, which should be available in PATH (and maybe it would be worthwhile to investigate and rewrite everything to work via openssl? — write your thoughts in the comments about that).


# Summary:

In the end you usually need to write some conclusions. Well.

If you want to enjoy learning/practice, come up with something that will be useful for you.

If you want to get double pleasure from learning / practice — come up with something that would be useful for you and somebody else.

Currently, my script is used by a small number of people in the company. And the fact that I, not a developer, was able to write something useful and necessary, makes me very happy.

P.S. Just in case (have you heard of nginx and Wargaming?), I want to state that jks_mgr.sh was written EXCLUSIVELY during non-working hours, on a private computer :).

P.P.S. https://github.com/sfkulyk/jks-manager