char *oauth_sign_rsa_sha1 (const char *m, const char *k) { unsigned char *sig = NULL; unsigned char *passphrase = NULL; unsigned int len=0; EVP_MD_CTX md_ctx; EVP_PKEY *pkey; BIO *in; in = BIO_new_mem_buf((unsigned char*) k, strlen(k)); pkey = PEM_read_bio_PrivateKey(in, NULL, 0, passphrase); // generate sign BIO_free(in); if (pkey == NULL) { //fprintf(stderr, "liboauth/OpenSSL: can not read private key\n"); return xstrdup("liboauth/OpenSSL: can not read private key"); } len = EVP_PKEY_size(pkey); sig = (unsigned char*)xmalloc((len+1)*sizeof(char)); EVP_SignInit(&md_ctx, EVP_sha1()); EVP_SignUpdate(&md_ctx, m, strlen(m)); if (EVP_SignFinal (&md_ctx, sig, &len, pkey)) { char *tmp; sig[len] = '\0'; tmp = oauth_encode_base64(len,sig); OPENSSL_free(sig); EVP_PKEY_free(pkey); return tmp; } return xstrdup("liboauth/OpenSSL: rsa-sha1 signing failed"); }
char *oauth_sign_rsa_sha1 (const char *m, const char *k) { PK11SlotInfo *slot = NULL; SECKEYPrivateKey *pkey = NULL; SECItem signature; SECStatus s; SECItem der; char *rv=NULL; char *key = oauth_strip_pkcs(k, NS_PRIV_HEADER, NS_PRIV_TRAILER); if (!key) return NULL; oauth_init_nss(); slot = PK11_GetInternalKeySlot(); if (!slot) goto looser; s = ATOB_ConvertAsciiToItem(&der, key); if (s != SECSuccess) goto looser; s = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &der, NULL, NULL, PR_FALSE, PR_TRUE, KU_ALL, &pkey, NULL); SECITEM_FreeItem(&der, PR_FALSE); if (s != SECSuccess) goto looser; if (!pkey) goto looser; if (pkey->keyType != rsaKey) goto looser; s = SEC_SignData(&signature, (unsigned char*) m, strlen(m), pkey, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE); if (s != SECSuccess) goto looser; rv=oauth_encode_base64(signature.len, signature.data); SECITEM_FreeItem(&signature, PR_FALSE); looser: if (pkey) SECKEY_DestroyPrivateKey(pkey); if (slot) PK11_FreeSlot(slot); free(key); return rv; }
/* API */ char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) { sha1nfo s; sha1_initHmac(&s, (const uint8_t*) k, kl); sha1_write(&s, m, ml); unsigned char *digest = sha1_resultHmac(&s); return oauth_encode_base64(HASH_LENGTH, digest); }
char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) { unsigned char result[EVP_MAX_MD_SIZE]; unsigned int resultlen = 0; HMAC(EVP_sha1(), k, kl, (unsigned char*) m, ml, result, &resultlen); return(oauth_encode_base64(resultlen, result)); }
char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) { PK11SlotInfo *slot = NULL; PK11SymKey *pkey = NULL; PK11Context *context = NULL; unsigned char digest[20]; // Is there a way to tell how large the output is? unsigned int len; SECStatus s; SECItem keyItem, noParams; char *rv=NULL; keyItem.type = siBuffer; keyItem.data = (unsigned char*) k; keyItem.len = kl; noParams.type = siBuffer; noParams.data = NULL; noParams.len = 0; oauth_init_nss(); slot = PK11_GetInternalKeySlot(); if (!slot) goto looser; pkey = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); if (!pkey) goto looser; context = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, pkey, &noParams); if (!context) goto looser; s = PK11_DigestBegin(context); if (s != SECSuccess) goto looser; s = PK11_DigestOp(context, (unsigned char*) m, ml); if (s != SECSuccess) goto looser; s = PK11_DigestFinal(context, digest, &len, sizeof digest); if (s != SECSuccess) goto looser; rv=oauth_encode_base64(len, digest); looser: if (context) PK11_DestroyContext(context, PR_TRUE); if (pkey) PK11_FreeSymKey(pkey); if (slot) PK11_FreeSlot(slot); return rv; }
get_pJWTAssertion(){ int rc=0; char * signature = 0; // Before getting here, example: lr_save_string("*****@*****.**","GoogleAPIServiceEmail"); // Each vuser gets its own tokens. // Google will return "Invalid Request' if the current time sent is off more than a just a few seconds from Google's server, so: // TODO: 14. Wherever machine this runs on needs to be synced to NTP or time.gov for UTC (GMT) timezone. // Google returns "invalid_grant" 400 error response if the previous token has not expired yet. // So loop is needed to re-use tokens until its expiration: lr_param_sprintf("pTimeNow","%d",time(0)); // where time(0) generates 10-digits. if( strcmp( lr_eval_string("{pTimeNow}"), lr_eval_string("{pTimeExpire}")) < 0 ){ wi_startPrintingTrace(); // Re-use assertion saved for use instead of running get_pJWTAssertion() again now. lr_output_message(">> JWT assertion token reuse: pTimeNow=%s, pTimeExpire=%s" ,lr_eval_string("{pTimeNow}") ,lr_eval_string("{pTimeExpire}") ); wi_stopPrinting(); } else { // First iteration or generated one expired: lr_param_sprintf("pTimeExpire","%d",time(0)+1800); // Google allows up to 3600 (one hour). } // The spec this should follow is http://tools.ietf.org/id/draft-jones-json-web-token-08.html#rfc.section.3.1 lr_param_sprintf("JWTBody", "{\"iss\":\"%s\"," "\"scope\":\"%s\"," "\"aud\":\"https://accounts.google.com/o/oauth2/token\"," "\"exp\":%s,\"iat\":%s}", lr_eval_string("{GoogleAPIServiceEmail}"), lr_eval_string("{pServiceScope}"), lr_eval_string("{pTimeExpire}"), lr_eval_string("{pTimeNow}")); // "aud" (audit) without back-slashes is: https://accounts.google.com/o/oauth2/token // "prn" (principal) is not set because it's not applicable for Gmail accounts, only Google Apps accounts granted domain-wide delegation access by an administrator. // Encode Header dot Claim set: lr_param_sprintf("pEncoded","%s.%s", oauth_url_escape(oauth_encode_base64(0,"{\"alg\":\"RS256\",\"typ\":\"JWT\"}")), oauth_url_escape(oauth_encode_base64(0,lr_eval_string("{JWTBody}")))); // "alg:RS256" = algorithm RSA P-256 SHA-256 used by Google APIs // "alg:HS256" = used by Google Wallet and OpenID // "alg:ES256" = algorithm ECDSA P-256 SHA-256 used by Salesforce // Microsoft Live Connect API signature = (char*)oauth_sign_rsa_sha256( lr_eval_string("{pEncoded}") ); lr_param_sprintf("pJWTAssertion","%s.%s", lr_eval_string("{pEncoded}"), oauth_url_escape(signature)); // Verify assertion output on-line using https://developers.google.com/commerce/wallet/digital/docs/jwtdecoder // https://developers.google.com/wallet/digital/docs/jwtdecoder wi_startPrintingTrace(); lr_output_message(">> JWTBody=%s." ,lr_eval_string("{JWTBody}") ); lr_output_message(">> pEncoded=%s." ,lr_eval_string("{pEncoded}") ); lr_output_message(">> pJWTAssertion=%s." ,lr_eval_string("{pJWTAssertion}") ); lr_output_message(">> signature=%s." ,signature ); wi_stopPrinting(); return rc; } // get_pJWTAssertion()
std::string oauth_sign_hmac_sha1_raw(const char *m, const size_t ml, const char *k, const size_t kl) { unsigned char result[20]; hmac_sha1((unsigned char const *)k, kl, (unsigned char const *)m, ml, result); return oauth_encode_base64(result, 20); }