Convert pem key to ssh-rsa format

后端 未结 8 994
耶瑟儿~
耶瑟儿~ 2020-11-29 16:03

I have a certificate in der format, from it with this command I generate a public key:

openssl x509 -inform der -in ejbcacert.cer -noout -pubkey         


        
相关标签:
8条回答
  • 2020-11-29 16:09

    To answer my own question, after posting on openssl mailing list got this:

    Here is C code to convert from an OpenSSL public key to an OpenSSH public key. You can grab the code from this link and compile it yourself:

    static unsigned char pSshHeader[11] = { 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61};
    
    static int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char* pBuffer)
    {
       int adjustedLen = bufferLen, index;
       if (*pBuffer & 0x80)
       {
          adjustedLen++;
          pEncoding[4] = 0;
          index = 5;
       }
       else
       {
          index = 4;
       }
       pEncoding[0] = (unsigned char) (adjustedLen >> 24);
       pEncoding[1] = (unsigned char) (adjustedLen >> 16);
       pEncoding[2] = (unsigned char) (adjustedLen >>  8);
       pEncoding[3] = (unsigned char) (adjustedLen      );
       memcpy(&pEncoding[index], pBuffer, bufferLen);
       return index + bufferLen;
    }
    
    int main(int argc, char**  argv)
    {
       int iRet = 0;
       int nLen = 0, eLen = 0;
       int encodingLength = 0;
       int index = 0;
       unsigned char *nBytes = NULL, *eBytes = NULL;
       unsigned char* pEncoding = NULL;
       FILE* pFile = NULL;
       EVP_PKEY *pPubKey = NULL;
       RSA* pRsa = NULL;
       BIO *bio, *b64;
    
       ERR_load_crypto_strings(); 
       OpenSSL_add_all_algorithms();
    
       if (argc != 3)
       {
          printf("usage: %s public_key_file_name ssh_key_description\n", argv[0]);
          iRet = 1;
          goto error;
       }
    
       pFile = fopen(argv[1], "rt");
       if (!pFile)
       {
          printf("Failed to open the given file\n");
          iRet = 2;
          goto error;
       }
    
       pPubKey = PEM_read_PUBKEY(pFile, NULL, NULL, NULL);
       if (!pPubKey)
       {
          printf("Unable to decode public key from the given file: %s\n", ERR_error_string(ERR_get_error(), NULL));
          iRet = 3;
          goto error;
       }
    
       if (EVP_PKEY_type(pPubKey->type) != EVP_PKEY_RSA)
       {
          printf("Only RSA public keys are currently supported\n");
          iRet = 4;
          goto error;
       }
    
       pRsa = EVP_PKEY_get1_RSA(pPubKey);
       if (!pRsa)
       {
          printf("Failed to get RSA public key : %s\n", ERR_error_string(ERR_get_error(), NULL));
          iRet = 5;
          goto error;
       }
    
       // reading the modulus
       nLen = BN_num_bytes(pRsa->n);
       nBytes = (unsigned char*) malloc(nLen);
       BN_bn2bin(pRsa->n, nBytes);
    
       // reading the public exponent
       eLen = BN_num_bytes(pRsa->e);
       eBytes = (unsigned char*) malloc(eLen);
       BN_bn2bin(pRsa->e, eBytes);
    
       encodingLength = 11 + 4 + eLen + 4 + nLen;
       // correct depending on the MSB of e and N
       if (eBytes[0] & 0x80)
          encodingLength++;
       if (nBytes[0] & 0x80)
          encodingLength++;
    
       pEncoding = (unsigned char*) malloc(encodingLength);
       memcpy(pEncoding, pSshHeader, 11);
    
       index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
       index = SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
    
       b64 = BIO_new(BIO_f_base64());
       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
       bio = BIO_new_fp(stdout, BIO_NOCLOSE);
       BIO_printf(bio, "ssh-rsa ");
       bio = BIO_push(b64, bio);
       BIO_write(bio, pEncoding, encodingLength);
       BIO_flush(bio);
       bio = BIO_pop(b64);
       BIO_printf(bio, " %s\n", argv[2]);
       BIO_flush(bio);
       BIO_free_all(bio);
       BIO_free(b64);
    
    error:
       if (pFile)
          fclose(pFile);
       if (pRsa)
          RSA_free(pRsa);
       if (pPubKey)
          EVP_PKEY_free(pPubKey);
       if (nBytes)
          free(nBytes);
       if (eBytes)
          free(eBytes);
       if (pEncoding)
          free(pEncoding);
    
       EVP_cleanup();
       ERR_free_strings();
       return iRet;
    }
    
    0 讨论(0)
  • 2020-11-29 16:16

    The following script would obtain the ci.jenkins-ci.org public key certificate in base64-encoded DER format and convert it to an OpenSSH public key file. This code assumes that a 2048-bit RSA key is used and draws a lot from this Ian Boyd's answer. I've explained a bit more how it works in comments to this article in Jenkins wiki.

    echo -n "ssh-rsa " > jenkins.pub
    curl -sfI https://ci.jenkins-ci.org/ | grep -i X-Instance-Identity | tr -d \\r | cut -d\  -f2 | base64 -d | dd bs=1 skip=32 count=257 status=none | xxd -p -c257 | sed s/^/00000007\ 7373682d727361\ 00000003\ 010001\ 00000101\ / | xxd -p -r | base64 -w0 >> jenkins.pub
    echo >> jenkins.pub
    
    0 讨论(0)
  • 2020-11-29 16:19

    No need to compile stuff. You can do the same with ssh-keygen:

    ssh-keygen -f pub1key.pub -i
    

    will read the public key in openssl format from pub1key.pub and output it in OpenSSH format.

    Note: In some cases you will need to specify the input format:

    ssh-keygen -f pub1key.pub -i -mPKCS8
    

    From the ssh-keygen docs (From man ssh-keygen):

    -m key_format Specify a key format for the -i (import) or -e (export) conversion options. The supported key formats are: “RFC4716” (RFC 4716/SSH2 public or private key), “PKCS8” (PEM PKCS8 public key) or “PEM” (PEM public key). The default conversion format is “RFC4716”.

    0 讨论(0)
  • 2020-11-29 16:20

    I did with

    ssh-keygen -i -f $sshkeysfile >> authorized_keys

    Credit goes here

    0 讨论(0)
  • 2020-11-29 16:21

    No need for scripts or other 'tricks': openssl and ssh-keygen are enough. I'm assuming no password for the keys (which is bad).

    Generate an RSA pair

    All the following methods give an RSA key pair in the same format

    1. With openssl (man genrsa)

      openssl genrsa -out dummy-genrsa.pem 2048
      

      In OpenSSL v1.0.1 genrsa is superseded by genpkey so this is the new way to do it (man genpkey):

      openssl genpkey -algorithm RSA -out dummy-genpkey.pem -pkeyopt rsa_keygen_bits:2048
      
    2. With ssh-keygen

      ssh-keygen -t rsa -b 2048 -f dummy-ssh-keygen.pem -N '' -C "Test Key"
      

    Converting DER to PEM

    If you have an RSA key pair in DER format, you may want to convert it to PEM to allow the format conversion below:

    Generation:

    openssl genpkey -algorithm RSA -out genpkey-dummy.cer -outform DER -pkeyopt rsa_keygen_bits:2048
    

    Conversion:

    openssl rsa -inform DER -outform PEM -in genpkey-dummy.cer -out dummy-der2pem.pem
    

    Extract the public key from the PEM formatted RSA pair

    1. in PEM format:

      openssl rsa -in dummy-xxx.pem -pubout
      
    2. in OpenSSH v2 format see:

      ssh-keygen -y -f dummy-xxx.pem
      

    Notes

    OS and software version:

    [user@test1 ~]# cat /etc/redhat-release ; uname -a ; openssl version
    CentOS release 6.5 (Final)
    Linux test1.example.local 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
    OpenSSL 1.0.1e-fips 11 Feb 2013
    

    References:

    • Sysmic.org Convert keys betweens GnuPG, OpenSsh and OpenSSL
    0 讨论(0)
  • 2020-11-29 16:22

    FWIW, this BASH script will take a PEM- or DER-format X.509 certificate or OpenSSL public key file (also PEM format) as the first argument and disgorge an OpenSSH RSA public key. This expands upon @mkalkov's answer above. Requirements are cat, grep, tr, dd, xxd, sed, xargs, file, uuidgen, base64, openssl (1.0+), and of course bash. All except openssl (contains base64) are pretty much guaranteed to be part of the base install on any modern Linux system, except maybe xxd (which Fedora shows in the vim-common package). If anyone wants to clean it up and make it nicer, caveat lector.

    #!/bin/bash
    #
    # Extract a valid SSH format public key from an X509 public certificate.
    #
    
    # Variables:
    pubFile=$1
    fileType="no"
    pkEightTypeFile="$pubFile"
    tmpFile="/tmp/`uuidgen`-pkEightTypeFile.pk8"
    
    # See if a file was passed:
    [ ! -f "$pubFile" ] && echo "Error, bad or no input file $pubFile." && exit 1
    
    # If it is a PEM format X.509 public cert, set $fileType appropriately:
    pemCertType="X$(file $pubFile | grep 'PEM certificate')"
    [ "$pemCertType" != "X" ] && fileType="PEM"
    
    # If it is an OpenSSL PEM-format PKCS#8-style public key, set $fileType appropriately:
    pkEightType="X$(grep -e '-BEGIN PUBLIC KEY-' $pubFile)"
    [ "$pkEightType" != "X" ] && fileType="PKCS"
    
    # If this is a file we can't recognise, try to decode a (binary) DER-format X.509 cert:
    if [ "$fileType" = "no" ]; then
            openssl x509 -in $pubFile -inform DER -noout
            derResult=$(echo $?)
            [ "$derResult" = "0" ] && fileType="DER"
    fi
    
    # Exit if not detected as a file we can use:
    [ "$fileType" = "no" ] && echo "Error, input file not of type X.509 public certificate or OpenSSL PKCS#8-style public key (not encrypted)." && exit 1
    
    # Convert the X.509 public cert to an OpenSSL PEM-format PKCS#8-style public key:
    if [ "$fileType" = "PEM" -o "$fileType" = "DER" ]; then
            openssl x509 -in $pubFile -inform $fileType -noout -pubkey > $tmpFile
            pkEightTypeFile="$tmpFile"
    fi
    
    # Build the string:
    # Front matter:
    frontString="$(echo -en 'ssh-rsa ')"
    
    # Encoded modulus and exponent, with appropriate pointers:
    encodedModulus="$(cat $pkEightTypeFile | grep -v -e "----" | tr -d '\n' | base64 -d | dd bs=1 skip=32 count=257 status=none | xxd -p -c257 | sed s/^/00000007\ 7373682d727361\ 00000003\ 010001\ 00000101\ / | xxd -p -r | base64 -w0 )"
    
    # Add a comment string based on the filename, just to be nice:
    commentString=" $(echo $pubFile | xargs basename | sed -e 's/\.crt\|\.cer\|\.pem\|\.pk8\|\.der//')"
    
    # Give the user a string:
    echo $frontString $encodedModulus $commentString
    
    # cleanup:
    rm -f $tmpFile
    
    0 讨论(0)
提交回复
热议问题