+/*
+ * RSAPrivateKey ::= SEQUENCE
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ */
+
+if ( !(s1 = Ustrstr(CS privkey_pem, "-----BEGIN RSA PRIVATE KEY-----"))
+ || !(s2 = Ustrstr(CS (s1+=31), "-----END RSA PRIVATE KEY-----" ))
+ )
+ return US"Bad PEM wrapper";
+
+*s2 = '\0';
+
+if ((der.len = b64decode(s1, &der.data)) < 0)
+ return US"Bad PEM-DER b64 decode";
+
+/* untangle asn.1 */
+
+/* sequence; just move past the header */
+if ((rc = as_tag(&der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
+ != ASN1_SUCCESS) goto asn_err;
+
+/* integer version; move past the header, check is zero */
+if ((rc = as_tag(&der, 0, ASN1_TAG_INTEGER, &alen)) != ASN1_SUCCESS)
+ goto asn_err;
+if (alen != 1 || *der.data != 0)
+ return US"Bad version number";
+der.data++; der.len--;
+
+if ( (s1 = as_mpi(&der, &sign_ctx->n))
+ || (s1 = as_mpi(&der, &sign_ctx->e))
+ || (s1 = as_mpi(&der, &sign_ctx->d))
+ || (s1 = as_mpi(&der, &sign_ctx->p))
+ || (s1 = as_mpi(&der, &sign_ctx->q))
+ || (s1 = as_mpi(&der, &sign_ctx->dp))
+ || (s1 = as_mpi(&der, &sign_ctx->dq))
+ || (s1 = as_mpi(&der, &sign_ctx->qp))
+ )
+ return s1;
+
+DEBUG(D_acl) acl_debug_printf("rsa_signing_init:\n");
+ {
+ uschar * s;
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->n);
+ acl_debug_printf(" N : %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->e);
+ acl_debug_printf(" E : %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->d);
+ acl_debug_printf(" D : %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->p);
+ acl_debug_printf(" P : %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->q);
+ acl_debug_printf(" Q : %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->dp);
+ acl_debug_printf(" DP: %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->dq);
+ acl_debug_printf(" DQ: %s\n", s);
+ gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->qp);
+ acl_debug_printf(" QP: %s\n", s);
+ }
+return NULL;
+
+asn_err: return US asn1_strerror(rc);
+}