SoftLayer API: Order Security Certificate CSR validation - ssl-certificate

I use the following openssl command to genereate CSR:
openssl genrsa -out mytestdomain.key 2048
openssl req -new -sha256 -key mytestdomain.key -out mytestdomain.csr
I try to place a Security Certificate order from SoftLayer customer portal using the aboved mytestdomain.csr value under the "Enter Certificate Signing Rquest (CSR) , I got an error msg :
"Must match CSR Base64 encoded PEM Format
---BEGIN CERTIFICATE REQUEST--- Base64 Encoded String
--End CERTIFICATE REQUEST ---
How to use openssl to generate Base64 encoded PEM CSR ?
If I enter a correct csr value from a sample file, I can see SoftLayer does a validation request as:
https://control.softlayer.com/security/sslorders/validatecsr
and the response shows valid email address, country such as :
{"success":true,"result":{"X":"XX","xx":"XXXX, Europe","L":"XXXX City","O":"My Test","OU":"VPN","XX":"mytest.com","emailAddress":"test#mytest.com"}}
Question 2: Which method can I use to validate and extract information from CSR, similar to what the SoftLayer customer portal use?

Regarding to your questions:
Question 1: I followed the steps in this link and it works successfully for me:
https://www.instantssl.com/ssl-certificate-support/csr-generation/ssl-certificate-mod-ssl.html
This will generate .key and .csr files. You should specify the .csr file content for CSR.
Question 2: The SoftLayer_Security_Certificate_Request::validateCsr method will help to validate the CSR.
Here a PHP example:
<?php
/**
* Validate Csr
*
* This script allows you to validate a Certificate Signing Request (CSR) required
* for an SSL certificate with the certificate authority (CA). This method sends the CSR,
* the length of the subscription in months, the certificate type, and the server type for
* validation against requirements of the CA. Returns true if valid.
*
* Important manual pages:
* #see http://sldn.softlayer.com/reference/services/SoftLayer_Security_Certificate_Request/validateCsr
*
* #license <http://sldn.softlayer.com/wiki/index.php/license>
* #author SoftLayer Technologies, Inc. <sldn#softlayer.com>
*/
require_once '\vendor\autoload.php';
/**
* Your SoftLayer API username and apiKey
* #var string
* #var string
*/
$apiUsername = 'set me';
$apiKey = 'set me';
/**
* The encoded CSR data string
* #var string
*/
$csr = "-----BEGIN CERTIFICATE REQUEST-----
MIIC9TCCAd0CAQAwga8xCzAJBgNVBAYTAkJPMRMwEQYDVQQIDApDb2NoYWJhbWJh
MRMwEQYDVQQHDApDb2NoYWJhbWJhMRUwEwYDVQQKDAxSdWJlckNvbXBhbnkxFTAT
BgNVBAsMDHJ1YmVyU2VjdGlvbjEdMBsGA1UEAwwUd3d3LnJ1YmVyY3VlbGxhci5j
b20xKTAnBgkqhkiG9w0BCQEWGnJ1YmVyLmN1ZWxsYXJAamFsYXNvZnQuY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw3WFBDFbqvk9O/6Wd+z0MsQQ
6WS5Vxw5iMVlo6J4xpoXqzA0FhuROv7IuJQ0rNvhDqTisMBLrUoDgvS6UgqM8RM9
DPNgGSdTVp0Z1Mt/qTavUPUfyT23msh5/Oqlo6/z+u23euKfTg4qhuVV7PG0eY6U
/GDumtmCk8+b33xzIBtLbfnB3119vRff9DmB6R7bSCzg+e8JnRycpSMKA8Egkw3N
O4k0mpvj5jR+FApFlTfKXcQU5xdEQYn1pe5+QLwSKJWP9iGEyiyFbvFVsYlKxKvh
RYEwuCqPAZBoWfO8zT4VPu2NO8QjDB55LX5xNAq2ZvHekbtWUtAzMeD6h2O04wID
AQABoAAwDQYJKoZIhvcNAQELBQADggEBAKcYJHvIvYzD+XssGHbfbyK7/arjGgyB
YyA5dx2DvwvdUGpIQyKCWyLyk10brObGoBGMtt5raxqI19UqnOpsOAJ5lF3fsM0B
mNQTAlsen/Ove/K+40Ycg1tYjLZN8vHebKvLyjENdeX4HgN+cTK030iUQq+ObwjB
te4UZsDhWlMijMay5gOcVZLI2D9uQzzMBgfymuuwync5m0ia1lmbNOmF9j9bNC5G
uN/rDbzGG4WEzbFmj/ERYgx7UGH9WkvEQA2+Dhj26SC3K9zgYkKMbaF3Kx49cBxj
xVtZtg+DLTQ8Ee5R/wB0YfGw1W3gYcVUBL/EZWv7PuqzKnBro09iuHA=
-----END CERTIFICATE REQUEST-----";
/**
* The product item identifier for the type of SSL certificate
* E.g: Item Id: 965 Description: RapidSSL - 2 year
* #var int
*/
$itemId = 965;
/**
* The type of server in which the certificate will be installed
* #var string
*/
$serverType = "apache2";
/**
* The length of the certificate subscription desired in months. Typically 12 or 24 months
* #var int
*/
$validityMonths = 24;
// Create a SoftLayer API client object for "SoftLayer_Security_Certificate_Request" service
$client = \SoftLayer\SoapClient::getClient('SoftLayer_Security_Certificate_Request', null, $apiUsername, $apiKey);
try {
$result = $client->validateCsr($csr, $validityMonths, $itemId, $serverType);
print_r($result);
} catch (\Exception $e) {
die('Unable to validated CSR: ' . $e->getMessage());
}
I hope this information can help you.

I'm not sure the types of CSR that are supported by SoftLayer, you can submit a ticket if you want more information about it.
However, if you want to validate the CSR, you can try with this: SSL Decoder, it is based on PHP. Also I extracted a little part of code from there, to get the result that you are expecting, try with this:
<?php
/**
* Function get_sans_from_csr
*/
function get_sans_from_csr($csr) {
global $random_blurp;
global $timeout;
$sans = array();
//openssl_csr_get_subject doesn't support SAN names.
$filename = "C:/Csr/tmp/csr-" . $random_blurp . "-" . gen_uuid() . ".csr.pem";
$write_csr = file_put_contents($filename, $csr);
if($write_csr !== FALSE) {
$openssl_csr_output = trim(shell_exec("timeout " . $timeout . " openssl req -noout -text -in " . $filename . " | grep -e 'DNS:' -e 'IP:'"));
}
unlink($filename);
if($openssl_csr_output) {
$csr_san_dns = explode("DNS:", $openssl_csr_output);
$csr_san_ip = explode("IP:", $openssl_csr_output);
if(count($csr_san_dns) > 1) {
foreach ($csr_san_dns as $key => $value) {
if($value) {
$san = trim(str_replace(",", "", str_replace("DNS:", "", $value)));
array_push($sans, $san);
}
}
}
if(count($csr_san_ip) > 1) {
foreach ($csr_san_ip as $key => $value) {
if($value) {
$san = trim(str_replace(",", "", str_replace("IP:", "", $value)));
array_push($sans, $san);
}
}
}
}
if(count($sans) >= 1) {
return $sans;
}
}
/**
* Function csr_parse_json
*/
function csr_parse_json($csr) {
// if csr or cert is pasted in form this function parses the csr or it send the cert to cert_parse.
global $random_blurp;
global $timeout;
$result = array();
if (strpos($csr, "BEGIN CERTIFICATE REQUEST") !== false) {
$cert_data = openssl_csr_get_public_key($csr);
$cert_details = openssl_pkey_get_details($cert_data);
$cert_key = $cert_details['key'];
$cert_subject = openssl_csr_get_subject($csr);
$result["subject"] = $cert_subject;
$result["key"] = $cert_key;
$result["details"] = $cert_details;
if ($cert_details) {
$result["csr_pem"] = $csr;
$sans = get_sans_from_csr($csr);
if(count($sans) > 1) {
$result["csr_sans"] = $sans;
}
}
} elseif (strpos($csr, "BEGIN CERTIFICATE") !== false) {
$result = cert_parse_json($csr, null, null, null, null, true);
} else {
$result = array("error" => "data not valid csr");
}
return $result;
}
/**
* Function gen_uuid
*/
function gen_uuid() {
//from stack overflow.
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
// 16 bits for "time_mid"
mt_rand( 0, 0xffff ),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand( 0, 0x0fff ) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand( 0, 0x3fff ) | 0x8000,
// 48 bits for "node"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
// Define your csr
$data = csr_parse_json("-----BEGIN CERTIFICATE REQUEST-----
MIIC9DCCAdwCAQAwga4xCzAJBgNVBAYTAkJPMRMwEQYDVQQIDApDb2NoYWJhbWJh
MRMwEQYDVQQHDApDb2NoYWJhbWJhMRkwFwYDVQQKDBBSdWJlclRlc3RDb21wYW55
MRAwDgYDVQQLDAdzZWN0aW9uMR0wGwYDVQQDDBR3d3cucnViZXJjdWVsbGFyLmNv
bTEpMCcGCSqGSIb3DQEJARYacnViZXIuY3VlbGxhckBqYWxhc29mdC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDw8QIBguC4qRsvb3I9K/2qO50g
zB3hEwb0DOCWa5LXUgpq3SHYohtlEdneUiRiYtn4ggO0NjZ4f4hfvQ9iZ10zH8/v
W7DeElvdJBP0dHEInuhKGP6wjieR2IkkPzsOTCeVJ6FOnxsC192qgXG0O8WjquKh
g6NZKdW0oLtl1/mWFixmWFwcjh7IUWZ/J0NpAlHBtDpYILRD84rHv1XK9GE1JUfO
euSwq6K0jRmK388Xt37bxFj5iMMpHXI55+LIpA9ZoV9NffCiGoohwp45QgEXdkfm
1NBGVXiGaQzn1HgnpdnYR05tAScOkqJ4yRkCUatE8q3F9+u8KM2e+mIxHeflAgMB
AAGgADANBgkqhkiG9w0BAQsFAAOCAQEA3TRZYZuhsQHmZ8anuMHawCcu6He5g3Yg
hpV4O06Knzblvdy9OvK1+jEPUEpTUGgyty0kU5WCru8+FL8+2/ycrUN8bisYDHlG
7KuzOuMxsz2/U/Vj3KAerv+/sIv2oDUN7otjA5smK6769gO1NjPPSXe/nDOPh3WC
YeRYRkLqCuTG6GfqmMK/o4vHrYXyxu6apvMId6PFmAEHqMZorebo8NyqvMA3pT1D
p+LuLZsqZWNsfX9iN31+PNCWvVKaDzF3z9vWmaDV61jiteRt0gOzun9GnRV2QRpS
5GjdY64A7dpB7VuVsnXePb5RbeWQQtMwwhuW01TzzlwB9yHwlel/hQ==
-----END CERTIFICATE REQUEST-----");
// Print whole result
print_r($data);
// Print "subject" property from the result
print_r($data["subject"]);
?>
All the methods used in the script were extracted from: SSL Decoder

Related

How to encrypt data with a public key using RSA method from phpseclib3?

I want to encrpypt some data with phpseclib3 with a public key. The example I found on the RSA.php file doesn't showing how to do encryption with a given public key.
here is the code example on the rsa.php
* <?php
* include 'vendor/autoload.php';
*
* $private = \phpseclib3\Crypt\RSA::createKey();
* $public = $private->getPublicKey();
*
* $plaintext = 'terrafrost';
*
* $ciphertext = $public->encrypt($plaintext);
*
* echo $private->decrypt($ciphertext);
* ?>
But, I want to use my key to do the encryption.
In my projects I'm loading the private and public key from a String but usually you will load the keys from a file (load a textfile in a variable should be no big problem :-).
My example is using OAES SHA-256 as encryption scheme:
function rsaEncryptionOaepSha256($publicKey, $plaintext) {
$rsa = PublicKeyLoader::load($publicKey)
->withHash('sha256')
->withMGFHash('sha256');
return $rsa->encrypt($plaintext);
}
function rsaDecryptionOaepSha256($privateKey, $ciphertext) {
$rsa = PublicKeyLoader::load($privateKey)
->withHash('sha256')
->withMGFHash('sha256');
return $rsa->decrypt($ciphertext);
}
function loadRsaPrivateKeyPem() {
// this is a sample key - don't worry !
return '
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDwSZYlRn86zPi9
...
3PIW4/CddNs8mCSBOqTnoaxh
-----END PRIVATE KEY-----
';
}
function loadRsaPublicKeyPem() {
// this is a sample key - don't worry !
return '
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8EmWJUZ/Osz4vXtUU2S+
...
QwIDAQAB
-----END PUBLIC KEY-----
';
}

How to verify PKCS#7 signature in PHP

I have a digital signature (encrypted format PKCS#7) needs to be verified So I have tried by using different PHP core methods(openssl_verify, openssl_pkcs7_verify and even tried by external library such as phpseclib But nothing worked :(
I get a signature along with some extra params through by this link..
http://URL?sign={'param':{'Id':'XXXXXXX','lang':'EN','Rc':'00','Email': 'test#yahoo.com'’},'signature':'DFERVgYJKoZIhvcNAQcCoIIFRzCCBUMCAQExCzAJBgUrDg
MCGgUAMIGCBgkqhkiG9w0BBwGgdQRzeyJEYXRlIjoidG9fY2hhcihzeXNkYXRlJ0RETU1ZWVlZJykgIiwiSWQiOiJ
VMDExODg3NyIsIklkaW9tYSI6IkNBUyIsIk51bUVtcCI6IlUwM23D4DEE3dSi...'}
PHP code - returns always 0(false) instead of 1(true).
$JSONDATA = str_replace("'", '"', #$_GET["sign"]);
$data = json_decode($JSONDATA, true);
$this->email = $data['param']["EMAIL"];
$this->signature = $data['signature'];
$this->signature_base64 = base64_decode($this->signature);
$this->dataencoded = json_encode($data['param']);
//SOLUTION 1 (By using phpseclib) but didnt work..
$rsa = $this->phpseclib->load();
$keysize = 2048;
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kver = $d['publickey'];
$KSign = $d['privatekey'];
// Signing
$rsa->loadKey($KSign);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');
$signature = $rsa->sign($this->dataencoded);
$signedHS = base64_encode($signature);
// Verification
$rsa->loadKey($Kver);
$status = $rsa->verify($this->dataencoded, $this->firma_base64); // getting an error on this line Message: Invalid signature
var_dump($status); // reutrn false
//SOLUTION 2 (By using code php methods)
// obtener la clave pública desde el certifiado y prepararla
$orignal_parse = parse_url("https://example.com", PHP_URL_HOST);
$get = stream_context_create(array("ssl" => array("capture_peer_cert" => TRUE)));
$read = stream_socket_client("ssl://".$orignal_parse.":443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
$cert = stream_context_get_params($read);
$certinfo = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
openssl_x509_export($cert["options"]["ssl"]["peer_certificate"],$cert_key);
$pubkeyid = openssl_pkey_get_public($cert_key);
$dataencoded = json_encode($data['param']);
echo $ok = openssl_x509_check_private_key($cert_key,$this->firma_base64); // return nothing
echo $ok1 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA256); // returns 0
echo $ok2 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA512); // returns 0
echo $ok3 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA256); // returns 0
echo $ok4 = openssl_verify($dataencoded, $this->firma, $pubkeyid, OPENSSL_ALGO_SHA512); // returns 0
Java code - (this code works and returns true)
private boolean verifySignautre(String frm) throws NetinfException, IOException, CMSException,
CertificateException, OperatorCreationException, Exception {
Security.addProvider(new BouncyCastleProvider());
//we extract the containers that make up the signature and the keystore used to sign included in the same signature.
CMSSignedData signedData = new CMSSignedData(Base64.decode(frm.getBytes()));
SignerInformationStore signers = signedData.getSignerInfos();
Store certStore = signedData.getCertificates();
Collection c = signers.getSigners();
Iterator it = c.iterator();
while (it.hasNext()) {
//retrieve the certificate with the recipient's id.
SignerInformation signerInfo = (SignerInformation) it.next();
Collection certCollection = certStore.getMatches(signerInfo.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder signerCertificateHolder = (X509CertificateHolder) certIt.next();
//create the container to validate signature.
ContentVerifierProvider contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new
DefaultDigestAlgorithmIdentifierFinder()).build(signerCertificateHolder);
//valid signature and then certificate validity date
try{
X509Certificate signedcert = new
JcaX509CertificateConverter().setProvider("BC").getCertificate(signerCertificateHolder);
signedcert.checkValidity();
signedcert.verify(signedcert.getPublicKey());
return true;
}catch(Exception e){
return false;
}
}
I simply need to convert this Java code into PHP. However, as you can see above that I tried different approaches but none of them worked.
Please support me to find the solution.
your support would be higly appreciated

JWT public key vs private key signature validation -- what is the difference?

I am using this library, node-jwks-rsa, to fetch JWT keys from my auth0 jwks.json file in order to verify that the id_token my application retrieves after authentication is actually coming from my auth provider.
Under the hood it uses this method to build a public key PEM
export function certToPEM(cert) {
cert = cert.match(/.{1,64}/g).join('\n');
cert = `-----BEGIN CERTIFICATE-----\n${cert}\n-----END CERTIFICATE-----\n`;
return cert;
}
(Using the x50c as argument from the .jwks file).
which I then use in combination with jsonwebtoken to verify that the JWT(id_token) is valid.
How is this method of verification different from generating a private key(RSA) from the modulus and exponent of the jwks.json file and using it for verification instead? (as example see this library)
Additionally here is function as demonstration that generates a PEM from a mod and exponent (taken from http://stackoverflow.com/questions/18835132/xml-to-pem-in-node-js)
export function rsaPublicKeyToPEM(modulusB64, exponentB64) {
const modulus = new Buffer(modulusB64, 'base64');
const exponent = new Buffer(exponentB64, 'base64');
const modulusHex = prepadSigned(modulus.toString('hex'));
const exponentHex = prepadSigned(exponent.toString('hex'));
const modlen = modulusHex.length / 2;
const explen = exponentHex.length / 2;
const encodedModlen = encodeLengthHex(modlen);
const encodedExplen = encodeLengthHex(explen);
const encodedPubkey = '30' +
encodeLengthHex(modlen + explen + encodedModlen.length / 2 + encodedExplen.length / 2 + 2) +
'02' + encodedModlen + modulusHex +
'02' + encodedExplen + exponentHex;
const der = new Buffer(encodedPubkey, 'hex')
.toString('base64');
let pem = `-----BEGIN RSA PUBLIC KEY-----\n`;
pem += `${der.match(/.{1,64}/g).join('\n')}`;
pem += `\n-----END RSA PUBLIC KEY-----\n`;
return pem;
};
The aforementioned jsonwebtoken library can verify a JWT using either -- but why? If both of these verification methods can validate a JWT signature why do they both exist? What are the tradeoffs between them? Is one more secure than the other? Which should I use to verify most fully?
Using a RSA assymetric key pair, the JWT is signed with the private key and verified with the public. You can not verify a digital signature with the private key
Modulus and exponent are the components of the public key and you can use it to build the public key in PEM format, which is a base64 representation of the public key (modulus and exponent) encoded in DER binary format. You can use PEM, DER or modulus and exponent because the contain the same information
But anybody can't build the private key with modulus and exponent. He would need the private RSA elements, which must be kept secret so that no one can sign for you.

creating pkcs12 return null in c code for mac project

I'm using openSSL to create a pkcs12 file in a mac project.
This method does not return null in my environment, but instead in the customer's environment. I'm unable to reproduce the problem in my environment.
Here is the code, what do you think ? should I install the openSSL library in the customer's environment? I'm new to this library.
thanks.
#include "PKCS12Util.h"
BUF_MEM* createPKCS12File(char* pkcs7_pem, BIO* pkey_bio, char* password, char* name) {
X509 *cert;
EVP_PKEY* pkey;
STACK_OF(X509) *cacert = sk_X509_new_null();
PKCS12 *pk12;
if (BIO_eof(pkey_bio)) {
BIO_reset(pkey_bio);
}
pkey = PEM_read_bio_PrivateKey(pkey_bio, NULL, NULL, NULL);
if (!pkey) {
fprintf(stderr, "Error constructing pkey from pkey_bio\n");
ERR_print_errors_fp(stderr);
}
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
pkcs7_pem = make_PEM(pkcs7_pem);
BIO *pkcs7_pem_bio = BIO_new_mem_buf((void *)pkcs7_pem, (int)strlen(pkcs7_pem));
PKCS7 *pkcs7 = PEM_read_bio_PKCS7(pkcs7_pem_bio, NULL, NULL, NULL);
if (!pkcs7) {
fprintf(stderr, "Error:\n");
ERR_print_errors_fp(stderr);
}
STACK_OF(X509) *pk7_certs = pkcs7->d.sign->cert;
// the first cert is the ca root cert, the last one is the client cert
cert = sk_X509_value(pk7_certs, sk_X509_num(pk7_certs) - 1);
sk_X509_push(cacert, sk_X509_value(pk7_certs, 0));
pk12 = PKCS12_create(password, name, pkey, cert, cacert, 0,0,0,0,0);
if(!pk12) {
fprintf(stderr, "Error creating PKCS#12 structure\n");
ERR_print_errors_fp(stderr);
return NULL;
}
BIO* pk12_bio = BIO_new(BIO_s_mem());
i2d_PKCS12_bio(pk12_bio, pk12);
// get the BUF_MEM from the BIO to return it
BUF_MEM *bptr;
BIO_get_mem_ptr(pk12_bio, &bptr);
BIO_set_close(pk12_bio, BIO_NOCLOSE); // So BIO_free() leaves BUF_MEM alone
PKCS12_free(pk12);
BIO_free(pkcs7_pem_bio);
BIO_free(pk12_bio);
return bptr;
}
I found the problem.
I was trying to compact a private key with a "MisMatched-Intermediate" certificate in the certificate chain.

Why do I get HTTP 401 Unauthorized from my call the to Yahoo contacts API?

This is driving me crackers. I'm implementing a friend invite scheme on a website and need access to the user's Yahoo contacts list. To do this, I'm using OAuth and the yahoo REST api. Here's a complete rundown of the sequence of events:
I have a project set up on developers.yahoo.com which is configured to have read access to Contacts. It's on a made-up domain which I point to 127.0.0.1 in my hosts file (On the off-chance that localhost was causing my woes). For this reason, the domain is not verified though my understanding is that this simply means I have less restrictions, not more.
Firstly, on the server I get a request token:
https://api.login.yahoo.com/oauth/v2/get_request_token
?oauth_callback=http%3A%2F%2Fdev.mysite.com%2Fcallback.aspx
&oauth_consumer_key=MYCONSUMERKEY--
&oauth_nonce=xmaf8ol87uxwkxij
&oauth_signature=WyWWIsjN1ANeiRpZxa73XBqZ2tQ%3D
&oauth_signature_method=HMAC-SHA1
&oauth_timestamp=1328796736
&oauth_version=1.0
Which returns with (Formatted for vague attempt at clarity):
oauth_token=hxcsqgj
&oauth_token_secret=18d01302348049830942830942630be6bee5
&oauth_expires_in=3600
&xoauth_request_auth_url
=https%3A%2F%2Fapi.login.yahoo.com%2Foauth%2Fv2%2Frequest_auth
%3Foauth_token%3Dhxcsqgj
&oauth_callback_confirmed=true"
I then pop-up the xoauth_request_auth_url page to the user and receive a verifier code to my callback page. I then send that back to my server so that I can exchange it for an access token:
https://api.login.yahoo.com/oauth/v2/get_token
?oauth_consumer_key=MYCONSUMERKEY--
&oauth_nonce=yxhd1nymwd03x189
&oauth_signature=c%2F6GTcybGJSQi4TOpvueLUO%2Fgrs%3D
&oauth_signature_method=HMAC-SHA1
&oauth_timestamp=1328796878
&oauth_token=hxcqgjs
&oauth_verifier=b8ngvp <- verifier given via callback
&oauth_version=1.0
That seems to work, and I get an access token back:
oauth_token=MYVERYLONGACCESSTOKEN--
&oauth_token_secret=MYOATHTOKENSECRET
&oauth_expires_in=3600
&oauth_session_handle=ADuXM093mTB4bgJPKby2lWeKvzrabvCrmjuAfrmA6mh5lEZUIin6
&oauth_authorization_expires_in=818686769
&xoauth_yahoo_guid=MYYAHOOGUID
I then immediately attempt to get the contacts list with the access token and the GUID:
http://social.yahooapis.com/v1/user/MYYAHOOGUID/contacts
(HTTP Header added and formatted with line breaks for clarity...)
Authorization: OAuth
realm="yahooapis.com",
oauth_consumer_key="MYCONSUMERKEY--",
oauth_nonce="nzffzj5v82mgf4mx",
oauth_signature="moVJywesuGaPN5YHYKqra4T2ips%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1328796907",
oauth_token="MYVERYLONGACCESSTOKEN--",
oauth_version="1.0"
From this call I get a 401 Unauthorized, but it seems impossible to find out why. To sign these calls, I'm using this oath lib on github. I don't think it's doing anything extraordinary or incompatable. For the signature, I'm including the consumer key/secret and the access token/secret. I've looked at the signature base that's being hashed and it looks to be the same form as the examples visible on yahoo's documentation. I'm guessing that I'm missing something from the parameters that isn't being hashed. Is there a way to find out why the call is unauthorized, or does anyone know of an example showing exactly what form the signature base and authorization header must take?
Solved this myself. Adding the answer just in case it happens to help anyone who makes the same silly mistake I did. When I made the API call, I was using the token secret returned from the original request token call instead of the new one returned from the access token call.
Oops.
this is the code with which I solved, the trusted code to use if yahooapis returns 403 forbidden:
Reference:
https://developer.yahoo.com/yql/guide/yql-code-examples.html#yql_php
https://github.com/danzisi/YQLQueryYahooapis
init CODE
/**
* Call the Yahoo Contact API
*
* https://developer.yahoo.com/yql/guide/yql-code-examples.html#yql_php
*
* #param string $consumer_key obtained when you registered your app
* #param string $consumer_secret obtained when you registered your app
* #param string $guid obtained from getacctok
* #param string $access_token obtained from getacctok
* #param string $access_token_secret obtained from getacctok
* #param bool $usePost use HTTP POST instead of GET
* #param bool $passOAuthInHeader pass the OAuth credentials in HTTP header
* #return response string with token or empty array on error
*/
function call_yql($consumer_key, $consumer_secret, $querynum, $access_token, $access_token_secret, $oauth_session_handle, $usePost=false, $passOAuthInHeader = true){
global $godebug;
$response = array();
if ($consumer_key=='' || $consumer_secret=='' || $querynum=='' || $access_token=='' || $access_token_secret=='' || $oauth_session_handle) return array('0' => 'Forbidden');
if ($querynum == 1) {
$url = 'https://query.yahooapis.com/v1/yql';
// Show my profile
$params['q'] = 'select * from social.profile where guid=me';
} elseif ($querynum == 2) {
$url = 'https://query.yahooapis.com/v1/yql';
// here other query
}
$params['format'] = 'json'; //json xml
$params['Authorization'] = 'OAuth';
$params['oauth_session_handle'] = $oauth_session_handle;
$params['realm'] = 'yahooapis.com';
$params['callback'] = 'cbfunc';
$params['oauth_version'] = '1.0';
$params['oauth_nonce'] = mt_rand();
$params['oauth_timestamp'] = time();
$params['oauth_consumer_key'] = $consumer_key;
$params['oauth_callback'] = 'oob';
$params['oauth_token'] = $access_token;
$params['oauth_signature_method'] = 'HMAC-SHA1';
$params['oauth_signature'] = oauth_compute_hmac_sig($usePost? 'POST' : 'GET', $url, $params, $consumer_secret, $access_token_secret);
if ($passOAuthInHeader) {
$query_parameter_string = oauth_http_build_query($params, true);
$header = build_oauth_header($params, "yahooapis.com");
$headers[] = $header;
} else {
$query_parameter_string = oauth_http_build_query($params);
}
// POST or GET the request
if ($usePost) {
$request_url = $url;
logit("call_yql:INFO:request_url:$request_url");
logit("call_yql:INFO:post_body:$query_parameter_string");
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$response = do_post($request_url, $query_parameter_string, 443, $headers);
} else {
$request_url = $url . ($query_parameter_string ? ('?' . $query_parameter_string) : '' );
logit("call_yql:INFO:request_url:$request_url");
$response = do_get($request_url, 443, $headers);
}
// extract successful response
if (! empty($response)) {
list($info, $header, $body) = $response;
if ($godebug==true) {
echo "<p>Debug: function call_yql info: <pre>" . print_r($info, TRUE) . "</pre></p>";
echo "<p>Debug: function call_yql header: <pre>" . print_r($header, TRUE) . "</pre></p>";
echo "<p>Debug: function call_yql body: <pre>" . print_r($body, TRUE) . "</pre></p>";
}
if ($body) {
$body = GetBetween($body, 'cbfunc(', ')');
$full_array_body = json_decode($body);
logit("call_yql:INFO:response:");
if ($godebug==true) echo "<p>Debug: function call_yql full_array_body: <pre>" . print_r($full_array_body, TRUE) . "</pre></p>";
}
}
// return object
return $full_array_body->query;
}
END code